Skip to content

Commit 147f223

Browse files
committed
[CE-115] Refine user auth api code structure
Refine user auth api Add user login history Move models into modules directory Change-Id: Ibd6058d72a4a8f97126073874b4a420f2eaf8b13 Signed-off-by: Haitao Yue <hightall@me.com>
1 parent ffa7404 commit 147f223

File tree

20 files changed

+270
-150
lines changed

20 files changed

+270
-150
lines changed

src/dashboard.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,22 @@
22
#
33
# SPDX-License-Identifier: Apache-2.0
44
#
5+
import logging
56
import os
6-
from common import log_handler, LOG_LEVEL
7+
8+
import bcrypt
79
from flask import Flask, render_template, redirect, url_for
10+
from flask_login import LoginManager
11+
from mongoengine import connect
12+
13+
from common import log_handler, LOG_LEVEL
14+
from modules.models import ADMIN
815
from resources import bp_index, \
916
bp_stat_view, bp_stat_api, \
1017
bp_cluster_view, bp_cluster_api, \
1118
bp_host_view, bp_host_api, bp_auth_api, \
1219
bp_login, bp_user_api, bp_user_view
13-
from resources.models import ADMIN
14-
from mongoengine import connect
15-
from flask_login import LoginManager, UserMixin, login_required
16-
from resources.user import User
17-
from resources import models
18-
import bcrypt
19-
import logging
20+
from modules.user import User
2021

2122
logger = logging.getLogger(__name__)
2223
logger.setLevel(LOG_LEVEL)

src/modules/models/__init__.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
2+
# Copyright IBM Corp, All Rights Reserved.
3+
#
4+
# SPDX-License-Identifier: Apache-2.0
5+
#
6+
from .user import ADMIN, OPERATOR, COMMON_USER, \
7+
User, LoginHistory

src/resources/models.py renamed to src/modules/models/user.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
import os
33
import datetime
44
from mongoengine import Document, StringField,\
5-
BooleanField, DateTimeField, IntField
5+
BooleanField, DateTimeField, IntField, \
6+
ReferenceField
67

78
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..'))
89

@@ -19,3 +20,8 @@ class User(Document):
1920
role = IntField(default=COMMON_USER)
2021
timestamp = DateTimeField(default=datetime.datetime.now)
2122
balance = IntField(default=0)
23+
24+
25+
class LoginHistory(Document):
26+
time = DateTimeField(default=datetime.datetime.now)
27+
user = ReferenceField(User)

src/modules/user/__init__.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,7 @@
33
#
44
# SPDX-License-Identifier: Apache-2.0
55
#
6-
from .management import ListUser, CreateUser, UpdateUser, DeleteUser
6+
from .management import ListUser, CreateUser, UpdateUser, \
7+
DeleteUser, UserInfo
8+
from .auth import Register, Login
9+
from .user import User

src/modules/user/auth/__init__.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
2+
# Copyright IBM Corp, All Rights Reserved.
3+
#
4+
# SPDX-License-Identifier: Apache-2.0
5+
#
6+
from .register import Register
7+
from .login import Login

src/modules/user/auth/login.py

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
2+
# Copyright IBM Corp, All Rights Reserved.
3+
#
4+
# SPDX-License-Identifier: Apache-2.0
5+
#
6+
from flask_restful import Resource, reqparse, fields, marshal_with
7+
from flask import url_for
8+
from flask_login import login_user, logout_user
9+
import logging
10+
import sys
11+
import os
12+
import bcrypt
13+
14+
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', '..'))
15+
from common import log_handler, LOG_LEVEL
16+
from modules.user.user import User
17+
18+
logger = logging.getLogger(__name__)
19+
logger.setLevel(LOG_LEVEL)
20+
logger.addHandler(log_handler)
21+
22+
login_fields = {
23+
"success": fields.Boolean,
24+
"id": fields.String,
25+
"next": fields.String,
26+
"error": fields.String
27+
}
28+
29+
login_parser = reqparse.RequestParser()
30+
login_parser.add_argument('username', required=True,
31+
location='form',
32+
help='Username for create')
33+
login_parser.add_argument('password', required=True,
34+
location='form',
35+
help='Password for create')
36+
37+
38+
class Login(Resource):
39+
@marshal_with(login_fields)
40+
def post(self, **kwargs):
41+
args = login_parser.parse_args()
42+
username, password = args["username"], args["password"]
43+
44+
user_obj = User()
45+
try:
46+
user = user_obj.get_by_username_w_password(username)
47+
if bcrypt.checkpw(password.encode('utf8'),
48+
bytes(user.password.encode())):
49+
login_user(user)
50+
user_id = str(user.id)
51+
data = {
52+
"success": True,
53+
"id": user_id,
54+
"next": url_for('bp_index.show')
55+
}
56+
return data, 200
57+
else:
58+
data = {
59+
"success": False,
60+
"error": "Wrong username or password"
61+
}
62+
return data, 401
63+
except Exception as exc:
64+
logger.info("error {}".format(exc))
65+
data = {
66+
"success": False,
67+
"error": "login failed"
68+
}
69+
return data, 401

src/modules/user/auth/register.py

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
2+
# Copyright IBM Corp, All Rights Reserved.
3+
#
4+
# SPDX-License-Identifier: Apache-2.0
5+
#
6+
from flask_restful import Resource, reqparse, fields, marshal_with
7+
from flask_login import login_required
8+
import logging
9+
import sys
10+
import os
11+
from flask import current_app as app
12+
import bcrypt
13+
14+
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', '..'))
15+
from common import log_handler, LOG_LEVEL
16+
from modules.models import ADMIN
17+
from modules.user.user import User
18+
19+
logger = logging.getLogger(__name__)
20+
logger.setLevel(LOG_LEVEL)
21+
logger.addHandler(log_handler)
22+
23+
register_fields = {
24+
"username": fields.String,
25+
"apikey": fields.String,
26+
"isActivated": fields.Boolean,
27+
"balance": fields.Integer,
28+
"success": fields.Boolean,
29+
"error": fields.String
30+
}
31+
32+
register_parser = reqparse.RequestParser()
33+
register_parser.add_argument('username', required=True,
34+
location='form',
35+
help='Username for create')
36+
register_parser.add_argument('password', required=True,
37+
location='form',
38+
help='Password for create')
39+
40+
41+
class Register(Resource):
42+
@login_required
43+
@marshal_with(register_fields)
44+
def post(self, **kwargs):
45+
args = register_parser.parse_args()
46+
username, password = args["username"], args["password"]
47+
salt = app.config.get("SALT", b"")
48+
password = bcrypt.hashpw(password.encode('utf8'), bytes(salt.encode()))
49+
50+
try:
51+
user = User(username, password)
52+
user_id = user.save()
53+
user = user.get_by_id(user_id)
54+
data = {
55+
"username": user.username,
56+
"apikey": str(user.id),
57+
"isActivated": user.active,
58+
"balance": user.balance,
59+
"success": True
60+
}
61+
return data, 200
62+
except Exception as exc:
63+
logger.error("exc %s", exc)
64+
data = {
65+
"success": False,
66+
"error": "register failed"
67+
}
68+
return data, 400

src/modules/user/management/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@
77
from .create import CreateUser
88
from .update import UpdateUser
99
from .delete import DeleteUser
10+
from .info import UserInfo

src/modules/user/management/create.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313

1414
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', '..'))
1515
from common import log_handler, LOG_LEVEL
16-
from resources.models import ADMIN
17-
from resources.user import User
16+
from modules.models import ADMIN
17+
from modules.user.user import User
1818

1919
logger = logging.getLogger(__name__)
2020
logger.setLevel(LOG_LEVEL)

src/modules/user/management/delete.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', '..'))
1313
from common import log_handler, LOG_LEVEL
14-
from resources.models import User as UserModel
14+
from modules.models import User as UserModel
1515

1616
logger = logging.getLogger(__name__)
1717
logger.setLevel(LOG_LEVEL)

src/modules/user/management/info.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
2+
# Copyright IBM Corp, All Rights Reserved.
3+
#
4+
# SPDX-License-Identifier: Apache-2.0
5+
#
6+
from flask_restful import Resource, fields, marshal_with
7+
from flask_login import login_required
8+
import logging
9+
import sys
10+
import os
11+
12+
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', '..'))
13+
from common import log_handler, LOG_LEVEL
14+
from modules.user.user import User
15+
16+
logger = logging.getLogger(__name__)
17+
logger.setLevel(LOG_LEVEL)
18+
logger.addHandler(log_handler)
19+
20+
user_info_fields = {
21+
"username": fields.String,
22+
"apikey": fields.String,
23+
"isActivated": fields.Boolean,
24+
"balance": fields.Integer,
25+
"success": fields.Boolean,
26+
"error": fields.String
27+
}
28+
29+
30+
class UserInfo(Resource):
31+
@marshal_with(user_info_fields)
32+
def get(self, user_id):
33+
user_obj = User()
34+
user = user_obj.get_by_id(user_id)
35+
if not user:
36+
return {"error": "No such User", "success": False}, 400
37+
38+
data = {
39+
"username": user.username,
40+
"apikey": str(user.id),
41+
"isActivated": user.active,
42+
"balance": user.balance,
43+
"success": True
44+
}
45+
46+
return data, 200

src/modules/user/management/list.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', '..'))
1313
from common import log_handler, LOG_LEVEL
14-
from resources.models import User as UserModel
14+
from modules.models import User as UserModel
1515
import time
1616

1717
logger = logging.getLogger(__name__)

src/modules/user/management/update.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', '..'))
1313
from common import log_handler, LOG_LEVEL
14-
from resources.models import User as UserModel
14+
from modules.models import User as UserModel
1515

1616
logger = logging.getLogger(__name__)
1717
logger.setLevel(LOG_LEVEL)

src/resources/user.py renamed to src/modules/user/user.py

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
import logging
44
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..'))
55
from flask_login import UserMixin, AnonymousUserMixin
6-
from resources import models
6+
from modules.models import User as UserModel
7+
from modules.models import LoginHistory
78
from common import log_handler, LOG_LEVEL
89

910
logger = logging.getLogger(__name__)
@@ -32,19 +33,19 @@ def user_role(self):
3233
return self.role
3334

3435
def save(self):
35-
new_user = models.User(username=self.username,
36-
password=self.password,
37-
active=self.active,
38-
role=self.role,
39-
balance=self.balance,
40-
isAdmin=self.isAdmin)
36+
new_user = UserModel(username=self.username,
37+
password=self.password,
38+
active=self.active,
39+
role=self.role,
40+
balance=self.balance,
41+
isAdmin=self.isAdmin)
4142
new_user.save()
4243
self.id = str(new_user.id)
4344
return self.id
4445

4546
def get_by_username(self, username):
4647

47-
dbUser = models.User.objects.get(username=username)
48+
dbUser = UserModel.objects.get(username=username)
4849
if dbUser:
4950
self.username = dbUser.username
5051
self.active = dbUser.active
@@ -56,7 +57,7 @@ def get_by_username(self, username):
5657

5758
def get_by_username_w_password(self, username):
5859
try:
59-
dbUser = models.User.objects.get(username=username)
60+
dbUser = UserModel.objects.get(username=username)
6061

6162
if dbUser:
6263
self.username = dbUser.username
@@ -65,6 +66,8 @@ def get_by_username_w_password(self, username):
6566
self.id = dbUser.id
6667
self.isAdmin = dbUser.isAdmin
6768
self.balance = dbUser.balance
69+
login_history = LoginHistory(user=dbUser)
70+
login_history.save()
6871
return self
6972
else:
7073
return None
@@ -74,7 +77,7 @@ def get_by_username_w_password(self, username):
7477

7578
def get_by_id(self, id):
7679
try:
77-
dbUser = models.User.objects.get(id=id)
80+
dbUser = UserModel.objects.get(id=id)
7881
except Exception:
7982
return None
8083
else:

src/resources/__init__.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
from .host_view import bp_host_view
1313

1414
from .stat import bp_stat_api, bp_stat_view
15-
from .auth_api import bp_auth_api
1615
from .login import bp_login
17-
from .user_api import bp_user_api
16+
from .user_api import bp_user_api, bp_auth_api
1817
from .user_view import bp_user_view

0 commit comments

Comments
 (0)