first commit
This commit is contained in:
82
super_bbs/controller/admin/account/api.py
Normal file
82
super_bbs/controller/admin/account/api.py
Normal file
@@ -0,0 +1,82 @@
|
||||
from flask import session, current_app
|
||||
from super_bbs.core.viewhandler import ApiViewHandler
|
||||
from super_bbs.model.users import Users, Passport, UserFavUser
|
||||
from super_bbs.model.topics import TopicFav
|
||||
from super_bbs.model.tabs import SubTabFav
|
||||
from super_bbs.utils import need_params, login_required
|
||||
from .wrapper import check_login
|
||||
|
||||
|
||||
class LoginAPI(ApiViewHandler):
|
||||
@need_params(*['username', 'password'])
|
||||
def post(self):
|
||||
user_obj = check_login(username=self.input.username, password=self.input.password)
|
||||
user_dict = user_obj.to_dict(remove_fields_list=['password'])
|
||||
session['is_login'] = True
|
||||
session['role_id'] = user_dict['role_id']
|
||||
session['user_info'] = user_dict
|
||||
# add token to passport
|
||||
passport = Passport.create_or_update(
|
||||
query_dict={'user_id': user_obj.id},
|
||||
update_dict={'token': session.sid}
|
||||
)
|
||||
passport.expire = self.get_datetime_now() + current_app.config['REMEMBER_COOKIE_DURATION']
|
||||
passport.save()
|
||||
|
||||
return user_dict
|
||||
|
||||
|
||||
class LoginOutAPI(ApiViewHandler):
|
||||
@login_required(admin=True)
|
||||
def get(self):
|
||||
session.clear()
|
||||
|
||||
def post(self):
|
||||
return self.get()
|
||||
|
||||
|
||||
class LoginStatusCheck(ApiViewHandler):
|
||||
def get(self):
|
||||
user_info = session.get('user_info')
|
||||
if user_info:
|
||||
user_obj = Users.get_by_id(user_info['id'])
|
||||
user_dict = user_obj.to_dict(remove_fields_list=['password'])
|
||||
user_dict['fav_sub_tab_count'] = SubTabFav.filter_by_query(user_id=user_dict['id']).count()
|
||||
user_dict['fav_topic_count'] = TopicFav.filter_by_query(user_id=user_dict['id']).count()
|
||||
user_dict['fav_user_count'] = UserFavUser.filter_by_query(user_id=user_dict['id']).count()
|
||||
session['user_info'] = user_dict
|
||||
return user_dict
|
||||
|
||||
|
||||
class ProfileAPI(ApiViewHandler):
|
||||
@login_required(admin=True)
|
||||
def get(self):
|
||||
user_obj = Users.get_by_id(session['user_info']['id'])
|
||||
user_dict = user_obj.to_dict(remove_fields_list=['password'])
|
||||
user_dict['fav_sub_tab_count'] = SubTabFav.filter_by_query(user_id=user_dict['id']).count()
|
||||
user_dict['fav_topic_count'] = TopicFav.filter_by_query(user_id=user_dict['id']).count()
|
||||
user_dict['fav_user_count'] = UserFavUser.filter_by_query(user_id=user_dict['id']).count()
|
||||
session['user_info'] = user_dict
|
||||
return user_dict
|
||||
|
||||
@login_required(admin=True)
|
||||
def post(self):
|
||||
user_info = session.get('user_info')
|
||||
user_obj = Users.get_by_uid(user_info['uid'])
|
||||
|
||||
update_dict = dict()
|
||||
|
||||
for k in ['sex', 'avatar_url', 'site', 'location', 'company', 'github', 'twitter', 'weibo', 'bio']:
|
||||
if getattr(self.input, k) is not None:
|
||||
update_dict[k] = getattr(self.input, k)
|
||||
if self.input.sex in [0, 1, 2]:
|
||||
update_dict['sex'] = self.input.sex
|
||||
|
||||
if self.input.privacy_level in [0, 1, 2]:
|
||||
update_dict['privacy_level'] = self.input.privacy_level
|
||||
|
||||
user_obj.update(**update_dict)
|
||||
user_info.update(update_dict)
|
||||
session['user_info'] = user_info
|
||||
|
||||
return user_info
|
||||
15
super_bbs/controller/admin/account/wrapper.py
Normal file
15
super_bbs/controller/admin/account/wrapper.py
Normal file
@@ -0,0 +1,15 @@
|
||||
from super_bbs.model.users import Users
|
||||
from super_bbs.core.basehandler import AuthError
|
||||
|
||||
|
||||
def check_login(username, password):
|
||||
user_obj = Users.filter_by_query(username=username).first()
|
||||
if not user_obj:
|
||||
raise AuthError("用户不存在")
|
||||
if not user_obj.check_password(password):
|
||||
raise AuthError("密码错误")
|
||||
if not user_obj.status:
|
||||
raise AuthError("账户已经停用")
|
||||
if user_obj.role_id != 1:
|
||||
raise AuthError("认证失败,账户不是超管")
|
||||
return user_obj
|
||||
78
super_bbs/controller/admin/comments/api.py
Normal file
78
super_bbs/controller/admin/comments/api.py
Normal file
@@ -0,0 +1,78 @@
|
||||
from flask import session
|
||||
from super_bbs.core.viewhandler import ApiViewHandler
|
||||
from super_bbs.model.topics import Topics
|
||||
from super_bbs.model.users import Users
|
||||
from super_bbs.model.comments import Comments
|
||||
from super_bbs.utils import need_params, login_required
|
||||
|
||||
|
||||
class CommentAPI(ApiViewHandler):
|
||||
@login_required(admin=True)
|
||||
def get(self):
|
||||
if self.input.uid:
|
||||
obj = Comments.get_by_uid(self.input.uid)
|
||||
data = obj.to_dict()
|
||||
data['user'] = Users.get_by_id(data['user_id']).to_dict(remove_fields_list=['password'])
|
||||
data['topic'] = Topics.get_by_id(data['topic_id']).to_dict()
|
||||
else:
|
||||
data = Comments.filter_by_query()
|
||||
if self.input.tab_id:
|
||||
data.filter_by_query(tab_id=self.input.tab_id)
|
||||
elif self.input.sub_tab_id:
|
||||
data.filter_by_query(sub_tab_id=self.input.sub_tab_id)
|
||||
if self.input.sk_ and self.input.sv_:
|
||||
data = data.filter(getattr(Comments, self.input.sk_).like(f'%{self.input.sv_}%'))
|
||||
|
||||
if self.input.odb_ and self.input.odt_ in ['asc', 'desc']:
|
||||
data = data.order_by(getattr(getattr(Comments, self.input.odb_), self.input.odt_)())
|
||||
else:
|
||||
data = data.order_by(Comments.time_create.desc())
|
||||
|
||||
total = None
|
||||
if self.input.page and self.input.page_size:
|
||||
total = data.count()
|
||||
data = data.offset(
|
||||
(int(self.input.page) - 1) * int(self.input.page_size)
|
||||
).limit(int(self.input.page_size))
|
||||
|
||||
data = [_t.to_dict() for _t in data]
|
||||
|
||||
user_dict = {
|
||||
i.id: i.to_dict(remove_fields_list=['password'])
|
||||
for i in Users.query.filter(
|
||||
Users.id.in_(set(i['user_id'] for i in data)),
|
||||
Users.available == 1
|
||||
)
|
||||
}
|
||||
topic_dict = {
|
||||
i.id: i.to_dict()
|
||||
for i in Topics.query.filter(
|
||||
Topics.id.in_(set(i['topic_id'] for i in data)),
|
||||
Topics.available == 1
|
||||
)
|
||||
}
|
||||
|
||||
for _d in data:
|
||||
_d['user'] = user_dict[_d['user_id']]
|
||||
_d['topic'] = topic_dict[_d['topic_id']]
|
||||
|
||||
if total is not None:
|
||||
data = {'total': total, 'list': data}
|
||||
|
||||
return data
|
||||
|
||||
@login_required(admin=True)
|
||||
@need_params(*['uid'])
|
||||
def put(self):
|
||||
obj = Comments.get_by_uid(self.input.uid)
|
||||
if self.input.content:
|
||||
obj.content = self.input.content
|
||||
if self.input.like_count:
|
||||
obj.like_count = self.input.like_count
|
||||
obj.save()
|
||||
|
||||
@login_required(admin=True)
|
||||
@need_params(*['uid'])
|
||||
def delete(self):
|
||||
obj = Comments.get_by_uid(self.input.uid)
|
||||
obj.update(available=0)
|
||||
158
super_bbs/controller/admin/tabs/api.py
Normal file
158
super_bbs/controller/admin/tabs/api.py
Normal file
@@ -0,0 +1,158 @@
|
||||
from collections import defaultdict
|
||||
from super_bbs.core.viewhandler import ApiViewHandler, LogicError
|
||||
from super_bbs.model.tabs import Tabs, SubTabs
|
||||
from super_bbs.utils import need_params, login_required
|
||||
|
||||
|
||||
class TabAPI(ApiViewHandler):
|
||||
@login_required(admin=True)
|
||||
def get(self):
|
||||
if self.input.uid:
|
||||
obj = Tabs.get_by_uid(self.input.uid)
|
||||
data = obj.to_dict()
|
||||
data['sub_tabs'] = [i.to_dict() for i in SubTabs.filter_by_query(tab_id=data['id'])]
|
||||
else:
|
||||
data = Tabs.filter_by_query()
|
||||
if self.input.sk_ and self.input.sv_:
|
||||
data = data.filter(getattr(Tabs, self.input.sk_).like(f'%{self.input.sv_}%'))
|
||||
|
||||
if self.input.odb_ and self.input.odt_ in ['asc', 'desc']:
|
||||
data = data.order_by(getattr(getattr(Tabs, self.input.odb_), self.input.odt_)())
|
||||
else:
|
||||
data = data.order_by(Tabs.time_create.asc())
|
||||
|
||||
total = None
|
||||
if self.input.page and self.input.page_size:
|
||||
total = data.count()
|
||||
data = data.offset(
|
||||
(int(self.input.page) - 1) * int(self.input.page_size)
|
||||
).limit(int(self.input.page_size))
|
||||
|
||||
data = [_t.to_dict() for _t in data]
|
||||
|
||||
sub_tab_dict_list = defaultdict(list)
|
||||
for sub_tab in SubTabs.filter_by_query().order_by(SubTabs.sort_num.asc()):
|
||||
sub_tab_dict_list[sub_tab.tab_id].append(sub_tab.to_dict())
|
||||
|
||||
for _d in data:
|
||||
_d['sub_tabs'] = sub_tab_dict_list.get(_d['id']) or []
|
||||
|
||||
if total is not None:
|
||||
data = {'total': total, 'list': data}
|
||||
|
||||
return data
|
||||
|
||||
@login_required(admin=True)
|
||||
@need_params(*['name', 'zh'])
|
||||
def post(self):
|
||||
obj = Tabs.create_by_uid()
|
||||
if not self.is_valid_name(self.input.name):
|
||||
raise LogicError('name 参数格式只能为英文')
|
||||
obj.name = self.input.name
|
||||
obj.zh = self.input.zh
|
||||
if self.input.sort_num:
|
||||
obj.sort_num = self.input.sort_num
|
||||
|
||||
obj.save()
|
||||
|
||||
@login_required(admin=True)
|
||||
@need_params(*['uid'])
|
||||
def put(self):
|
||||
obj = Tabs.get_by_uid(self.input.uid)
|
||||
if self.input.name:
|
||||
if not self.is_valid_name(self.input.name):
|
||||
raise LogicError('name 参数格式只能为英文')
|
||||
obj.name = self.input.name
|
||||
if self.input.zh:
|
||||
obj.zh = self.input.zh
|
||||
if self.input.sort_num:
|
||||
obj.sort_num = self.input.sort_num
|
||||
obj.save()
|
||||
|
||||
@login_required(admin=True)
|
||||
@need_params(*['uid'])
|
||||
def delete(self):
|
||||
obj = Tabs.get_by_uid(self.input.uid)
|
||||
if SubTabs.filter_by_query(tab_id=obj.id).all():
|
||||
raise LogicError('存在子类别无法删除')
|
||||
obj.update(available=0)
|
||||
|
||||
|
||||
class SubTabAPI(ApiViewHandler):
|
||||
@login_required(admin=True)
|
||||
def get(self):
|
||||
if self.input.uid:
|
||||
obj = SubTabs.get_by_uid(self.input.uid)
|
||||
data = obj.to_dict()
|
||||
data['tab'] = Tabs.get_by_id(obj.tab_id).to_dict()
|
||||
else:
|
||||
if self.input.tab_id:
|
||||
data = SubTabs.filter_by_query(tab_id=self.input.tab_id)
|
||||
else:
|
||||
data = SubTabs.filter_by_query()
|
||||
if self.input.sk_ and self.input.sv_:
|
||||
data = data.filter(getattr(SubTabs, self.input.sk_).like(f'%{self.input.sv_}%'))
|
||||
|
||||
if self.input.odb_ and self.input.odt_ in ['asc', 'desc']:
|
||||
data = data.order_by(getattr(getattr(SubTabs, self.input.odb_), self.input.odt_)())
|
||||
else:
|
||||
data = data.order_by(SubTabs.time_create.desc())
|
||||
|
||||
total = None
|
||||
if self.input.page and self.input.page_size:
|
||||
total = data.count()
|
||||
data = data.offset(
|
||||
(int(self.input.page) - 1) * int(self.input.page_size)
|
||||
).limit(int(self.input.page_size))
|
||||
|
||||
data = [_t.to_dict() for _t in data]
|
||||
tab_dict = {
|
||||
i.id: i.to_dict()
|
||||
for i in Tabs.filter_by_query()
|
||||
}
|
||||
|
||||
for d in data:
|
||||
d['tab'] = tab_dict[d['tab_id']]
|
||||
|
||||
if total is not None:
|
||||
data = {'total': total, 'list': data}
|
||||
|
||||
return data
|
||||
|
||||
@login_required(admin=True)
|
||||
@need_params(*['tab_id', 'name', 'zh'])
|
||||
def post(self):
|
||||
obj = SubTabs.create_by_uid()
|
||||
_tab_obj = Tabs.get_by_id(self.input.tab_id)
|
||||
obj.tab_id = self.input.tab_id
|
||||
if not self.is_valid_name(self.input.name):
|
||||
raise LogicError('name 参数格式只能为英文')
|
||||
obj.name = self.input.name
|
||||
obj.zh = self.input.zh
|
||||
if self.input.desc:
|
||||
obj.desc = self.input.desc
|
||||
if self.input.sort_num:
|
||||
obj.sort_num = self.input.sort_num
|
||||
obj.save()
|
||||
|
||||
@login_required(admin=True)
|
||||
@need_params(*['uid'])
|
||||
def put(self):
|
||||
obj = SubTabs.get_by_uid(self.input.uid)
|
||||
if self.input.name:
|
||||
if not self.is_valid_name(self.input.name):
|
||||
raise LogicError('name 参数格式只能为英文')
|
||||
obj.name = self.input.name
|
||||
if self.input.zh:
|
||||
obj.zh = self.input.zh
|
||||
if self.input.desc:
|
||||
obj.name = self.input.desc
|
||||
if self.input.sort_num:
|
||||
obj.sort_num = self.input.sort_num
|
||||
obj.save()
|
||||
|
||||
@login_required(admin=True)
|
||||
@need_params(*['uid'])
|
||||
def delete(self):
|
||||
obj = SubTabs.get_by_uid(self.input.uid)
|
||||
obj.update(available=0)
|
||||
149
super_bbs/controller/admin/topics/api.py
Normal file
149
super_bbs/controller/admin/topics/api.py
Normal file
@@ -0,0 +1,149 @@
|
||||
from collections import defaultdict
|
||||
from flask import session
|
||||
from super_bbs.core.viewhandler import ApiViewHandler
|
||||
from super_bbs.model.topics import Topics, TopicAppends, Tags, TopicToTag, TopicUpDown
|
||||
from super_bbs.model.users import Users
|
||||
from super_bbs.model.tabs import Tabs, SubTabs
|
||||
from super_bbs.model.comments import Comments
|
||||
from super_bbs.utils import need_params, login_required
|
||||
|
||||
|
||||
class TopicAPI(ApiViewHandler):
|
||||
@login_required(admin=True)
|
||||
def get(self):
|
||||
if self.input.uid:
|
||||
obj = Topics.get_by_uid(self.input.uid)
|
||||
data = obj.to_dict()
|
||||
data['user'] = Users.get_by_id(data['user_id']).to_dict(remove_fields_list=['password'])
|
||||
if data['last_reply_user_id']:
|
||||
data['last_reply_user'] = Users.get_by_id(data['last_reply_user_id']).to_dict(remove_fields_list=['password'])
|
||||
data['tab'] = Tabs.get_by_id(data['tab_id']).to_dict()
|
||||
data['sub_tab'] = SubTabs.get_by_id(data['sub_tab_id']).to_dict()
|
||||
data['appends'] = [i.to_dict() for i in TopicAppends.filter_by_query(topic_id=data['id'])]
|
||||
comment_list = [i.to_dict() for i in Comments.filter_by_query(topic_id=data['id'])]
|
||||
comment_user_dict = {
|
||||
i.id: i.to_dict()
|
||||
for i in Users.query.filter(
|
||||
Users.id.in_(set(i['user_id'] for i in comment_list)),
|
||||
Users.available == 1
|
||||
)
|
||||
}
|
||||
for comment in comment_list:
|
||||
comment['user'] = comment_user_dict[comment['user_id']]
|
||||
data['comments'] = comment_list
|
||||
data['comment_count'] = len(comment_list)
|
||||
data['up_count'] = TopicUpDown.filter_by_query(topic_id=data['id'], action=True).count()
|
||||
data['down_count'] = TopicUpDown.filter_by_query(topic_id=data['id'], action=False).count()
|
||||
else:
|
||||
data = Topics.filter_by_query()
|
||||
if self.input.tab_id:
|
||||
data.filter_by_query(tab_id=self.input.tab_id)
|
||||
elif self.input.sub_tab_id:
|
||||
data.filter_by_query(sub_tab_id=self.input.sub_tab_id)
|
||||
if self.input.sk_ and self.input.sv_:
|
||||
data = data.filter(getattr(Topics, self.input.sk_).like(f'%{self.input.sv_}%'))
|
||||
|
||||
if self.input.odb_ and self.input.odt_ in ['asc', 'desc']:
|
||||
data = data.order_by(getattr(getattr(Topics, self.input.odb_), self.input.odt_)())
|
||||
else:
|
||||
data = data.order_by(Topics.time_create.desc())
|
||||
|
||||
total = None
|
||||
if self.input.page and self.input.page_size:
|
||||
total = data.count()
|
||||
data = data.offset(
|
||||
(int(self.input.page) - 1) * int(self.input.page_size)
|
||||
).limit(int(self.input.page_size))
|
||||
|
||||
data = [_t.to_dict() for _t in data]
|
||||
|
||||
user_dict = {
|
||||
i.id: i.to_dict(remove_fields_list=['password'])
|
||||
for i in Users.query.filter(
|
||||
Users.id.in_(set(i['user_id'] for i in data)),
|
||||
Users.available == 1
|
||||
)
|
||||
}
|
||||
|
||||
last_reply_user_dict = {
|
||||
i.id: i.to_dict(remove_fields_list=['password'])
|
||||
for i in Users.query.filter(
|
||||
Users.id.in_(set(i['last_reply_user_id'] for i in data)),
|
||||
Users.available == 1
|
||||
)
|
||||
}
|
||||
|
||||
tab_dict = {
|
||||
i.id: i.to_dict()
|
||||
for i in Tabs.query.filter(
|
||||
Tabs.id.in_(set(i['tab_id'] for i in data)),
|
||||
Tabs.available == 1
|
||||
)
|
||||
}
|
||||
|
||||
sub_tab_dict = {
|
||||
i.id: i.to_dict()
|
||||
for i in SubTabs.query.filter(
|
||||
SubTabs.id.in_(set(i['sub_tab_id'] for i in data)),
|
||||
SubTabs.available == 1
|
||||
)
|
||||
}
|
||||
|
||||
comment_count_dict = dict()
|
||||
for c in Comments.query.filter(Comments.topic_id.in_(set(i['id'] for i in data)), Comments.available == 1):
|
||||
if comment_count_dict.get(c.topic_id):
|
||||
comment_count_dict[c.topic_id] += 1
|
||||
else:
|
||||
comment_count_dict[c.topic_id] = 1
|
||||
|
||||
up_down_dict_list = defaultdict(list)
|
||||
for up_down_obj in TopicUpDown.query.filter(
|
||||
TopicUpDown.topic_id.in_(set(i['id'] for i in data)),
|
||||
TopicUpDown.available == 1
|
||||
):
|
||||
up_down_dict_list[up_down_obj.topic_id].append(up_down_obj.action)
|
||||
|
||||
for _d in data:
|
||||
_d['user'] = user_dict[_d['user_id']]
|
||||
if _d['last_reply_user_id']:
|
||||
_d['last_reply_user'] = last_reply_user_dict[_d['last_reply_user_id']]
|
||||
_d['tab'] = tab_dict[_d['tab_id']]
|
||||
_d['sub_tab'] = sub_tab_dict[_d['sub_tab_id']]
|
||||
_d['comment_count'] = comment_count_dict.get(_d['id'], 0)
|
||||
# 获取up和down数量
|
||||
if up_down_dict_list.get(_d['id']):
|
||||
_d['up_count'] = len([i for i in up_down_dict_list[_d['id']] if i is True])
|
||||
_d['down_count'] = len([i for i in up_down_dict_list[_d['id']] if i is False])
|
||||
else:
|
||||
_d['up_count'] = 0
|
||||
_d['down_count'] = 0
|
||||
|
||||
if total is not None:
|
||||
data = {'total': total, 'list': data}
|
||||
|
||||
return data
|
||||
|
||||
@login_required(admin=True)
|
||||
@need_params(*['uid'])
|
||||
def put(self):
|
||||
obj = Topics.get_by_uid(self.input.uid)
|
||||
if self.input.title:
|
||||
obj.title = self.input.title
|
||||
if self.input.content:
|
||||
obj.content = self.input.content
|
||||
obj.content_length = len(self.input.content)
|
||||
if self.input.sub_tab_id:
|
||||
sub_tab_obj = SubTabs.get_by_id(self.input.sub_tab_id)
|
||||
obj.sub_tab_id = sub_tab_obj.id
|
||||
obj.tab_id = sub_tab_obj.tab_id
|
||||
obj.save()
|
||||
|
||||
@login_required(admin=True)
|
||||
@need_params(*['uid'])
|
||||
def delete(self):
|
||||
obj = Topics.get_by_uid(self.input.uid)
|
||||
for tmp_obj in TopicAppends.filter_by_query(topic_id=obj.id):
|
||||
tmp_obj.update(available=0)
|
||||
for tmp_obj in Comments.filter_by_query(topic_id=obj.id):
|
||||
tmp_obj.update(available=0)
|
||||
obj.update(available=0)
|
||||
44
super_bbs/controller/admin/users/api.py
Normal file
44
super_bbs/controller/admin/users/api.py
Normal file
@@ -0,0 +1,44 @@
|
||||
from super_bbs.core.viewhandler import ApiViewHandler
|
||||
from super_bbs.model.users import Users
|
||||
from super_bbs.utils import need_params, login_required
|
||||
|
||||
|
||||
class UserAPI(ApiViewHandler):
|
||||
@login_required(admin=True)
|
||||
def get(self):
|
||||
if self.input.uid:
|
||||
obj = Users.get_by_uid(self.input.uid)
|
||||
data = obj.to_dict(remove_fields_list=['password'])
|
||||
else:
|
||||
data = Users.filter_by_query()
|
||||
if self.input.sk_ and self.input.sv_:
|
||||
data = data.filter(getattr(Users, self.input.sk_).like(f'%{self.input.sv_}%'))
|
||||
|
||||
if self.input.odb_ and self.input.odt_ in ['asc', 'desc']:
|
||||
data = data.order_by(getattr(getattr(Users, self.input.odb_), self.input.odt_)())
|
||||
else:
|
||||
data = data.order_by(Users.time_create.desc())
|
||||
|
||||
total = None
|
||||
if self.input.page and self.input.page_size:
|
||||
total = data.count()
|
||||
data = data.offset(
|
||||
(int(self.input.page) - 1) * int(self.input.page_size)
|
||||
).limit(int(self.input.page_size))
|
||||
|
||||
data = [_t.to_dict(remove_fields_list=['password']) for _t in data]
|
||||
|
||||
if total is not None:
|
||||
data = {'total': total, 'list': data}
|
||||
|
||||
return data
|
||||
|
||||
@login_required(admin=True)
|
||||
@need_params(*['uid'])
|
||||
def put(self):
|
||||
obj = Users.get_by_uid(self.input.uid)
|
||||
if self.input.status:
|
||||
obj.status = self.input.status
|
||||
if self.input.role_id:
|
||||
obj.role_id = self.input.role_id
|
||||
obj.save()
|
||||
Reference in New Issue
Block a user