def test_dissert(self): objs = [ {"accounts": {"actions": {"add": "", "delete": "", "edit": ""}}, "proftpd": {"ftp_client": {"access": "self", "type": {"write": {"access_change": ""}}}, "statistics": "self", "daemon": ""}}, {"accounts": {"actions": {"add": "", "delete": "", "edit": ""}}}, {"proftpd": {"ftp_client": {"access": "self", "type": {"write": {"access_change": ""}}}, "statistics": "self", "daemon": ""}}, {"accounts": {"actions": {"add": "", "delete": "", "edit": ""}}, "proftpd": {"ftp_client": {"access": "self", "type": {"write": {"access_change": ""}}}, "statistics": "self", "daemon": ""}}, {"proftpd": {"ftp_client": {"access": "self", "type": {"write": {"access_change": ""}}}, "statistics": "self", "daemon": ""}} ] dissect = [ {"accounts": {"actions": {"add": "", "edit": ""}}, "proftpd": {"ftp_client": {"access": "self", "type": "read"}, "statistics": "self", "daemon": ""}}, {"accounts": {"actions": {"add": ""}}, "proftpd": {"ftp_client": {"type": {"write": {"access_change": ""}}}}}, {"proftpd": {"ftp_client": {"access": "self", "type": "read"}, "statistics": "self", "daemon": ""}}, {"accounts": {"actions": {"add": "", "delete": "", "edit": ""}}}, {"proftpd": {"ftp_client": {"access": "self", "type": {"write": {"access_change": ""}}}, "statistics": "self", "daemon": ""}}, ] result = [ {'proftpd': {'ftp_client': {'type': {"write": {"access_change": ""}}}}, 'accounts': {'actions': {'delete': ''}}}, {"accounts": {"actions": {"delete": "", "edit": ""}}}, {"proftpd": {"ftp_client": {"type": {"write": {"access_change": ""}}}}}, {"proftpd": {"ftp_client": {"access": "self", "type": {"write": {"access_change": ""}}}, "statistics": "self", "daemon": ""}}, {} ] i = 0 for o in objs: perm_obj = Permission(o) perm_obj.dissect(dissect[i]) self.assertTrue(perm_obj.permissions == result[i]) i += 1
def test_merge(self): objs = [ {"accounts": {"actions": {"add": "", "delete": "", "edit": ""}}}, {}, {"proftpd": {"ftp_client": {"access": "self", "type": "read"}, "statistics": "self", "daemon": ""}}, {"accounts": {"actions": {"edit": "", "delete": ""}}}, {"proftpd": {"ftp_client": {"access": "self", "type": "read"}}} ] merge = [ {"proftpd": {"ftp_client": {"access": "self", "type": "read"}, "statistics": "self", "daemon": ""}}, {}, {"proftpd": {"ftp_client": {"access": "self", "type": {"write": {"access_change": ""}}}, "statistics": "self", "daemon": ""}}, {"accounts": {"actions": {"add": ""}}}, {"proftpd": {"ftp_client": {"access": "global", "type": {"write": {"access_change": ""}}}, "statistics": "self", "daemon": ""}} ] result = [ {"accounts": {"actions": {"add": "", "delete": "", "edit": ""}}, "proftpd": {"ftp_client": {"access": "self", "type": "read"}, "statistics": "self", "daemon": ""}}, {}, {"proftpd": {"ftp_client": {"access": "self", "type": {"write": {"access_change": ""}}}, "statistics": "self", "daemon": ""}}, {"accounts": {"actions": {"edit": "", "delete": "", "add": ""}}}, {"proftpd": {"ftp_client": {"access": "global", "type": {"write": {"access_change": ""}}}, "statistics": "self", "daemon": ""}} ] i = 0 for o in objs: perm_obj = Permission(o) perm_obj.merge(merge[i]) self.assertTrue(perm_obj.permissions == result[i]) i += 1
def merged_permissions(self): cache_key = CACHE_KEY_USERPERM % self.id if not cache.get(cache_key): permission = Permission(self.profile.permissions) cache.set(cache_key, permission.merge(self.group_permissions())) return cache.get(cache_key)
def group_permissions(self): cache_key = CACHE_KEY_UGRPERM % self.id if not cache.get(cache_key): group_perms = Permission() for group in self.groups.all(): group_perms.merge(group.permissions) cache.set(cache_key, group_perms.permissions) return cache.get(cache_key)
def delete(self, args_, current_user): """ 删除用户,逻辑删除 :return: """ res = AppSetting.general_result() res["request_info"] = self.request_info if not Permission.check_user_role(self.edit_roles, current_user["roles"]): res["err_code"] = APIStatus.ROLE_FORBIDDEN res["message"] = "user role is forbidden: {}".format( current_user["username"]) res["result"] = "fail" return res if "item" not in args_ or not args_["item"]: res["err_code"] = APIStatus.FIELD_LACK res["message"] = "no such params: item" res["result"] = "fail" return res res["data"] = {"uid": args_.get("item", "")} try: self.controller.delete(args_["item"]) except SQLAlchemyError as err: # print(err.orig.args) res["err_code"] = APIStatus.DB_ERROR res["message"] = json.dumps(err.orig.args) res["result"] = "fail" except Exception as err: res["err_code"] = APIStatus.UNDEFINED res["message"] = str(err) res["result"] = "fail" else: res["err_code"] = APIStatus.SUCCESS return res
def get(self, args_, current_user): """ 获取用户信息 :return: """ res = AppSetting.general_result() res["request_info"] = self.request_info if not Permission.check_user_role(self.view_roles, current_user["roles"]): res["err_code"] = APIStatus.ROLE_FORBIDDEN res["message"] = "user role is forbidden: {}".format( current_user["username"]) res["result"] = "fail" return res order_key = args_.get("order_key", "-create_time") if order_key: if order_key.startswith("-"): key_check = order_key[1:] else: key_check = order_key if key_check not in self.fields_border: res["err_code"] = APIStatus.FIELD_OUTER res["message"] = "order_key: [{}] is unknown field".format( key_check) res["result"] = "fail" return res start = args_.get("start", 0) count = args_.get("count", 0) start = start if isinstance(start, int) and start >= 0 else 0 count = count if isinstance(count, int) and count >= 0 else 0 try: total = self.controller.count() res["data"] = self.controller.all( start=start, count=count, order_key=order_key) or [] except SQLAlchemyError as err: # print(err.orig.args) res["err_code"] = APIStatus.DB_ERROR res["message"] = json.dumps(err.orig.args) res["result"] = "fail" except Exception as err: res["err_code"] = APIStatus.UNDEFINED res["message"] = str(err) res["result"] = "fail" else: res["err_code"] = APIStatus.SUCCESS res["total"] = total return res
def put(self, args_, body_, current_user): """ 更改用户信息 :return: """ res = AppSetting.general_result() res["request_info"] = self.request_info if not Permission.check_user_role(self.edit_roles, current_user["roles"]): res["err_code"] = APIStatus.ROLE_FORBIDDEN res["message"] = "user role is forbidden: {}".format( current_user["username"]) res["result"] = "fail" return res if "item" not in args_ or not args_["item"]: res["err_code"] = APIStatus.FIELD_LACK res["message"] = "no such params: item" res["result"] = "fail" return res res["data"] = {"uid": args_.get("item", "")} for field in list(body_.keys()): if field not in self.fields_border: body_.pop(field) # print(body_) unique_list = deepcopy(self.controller.get_model().unique_list) unique_list.append(self.controller.get_model().key_word) try: self._check_unique_field(body_, unique_list) except Exception as err: res["err_code"] = APIStatus.ALREADY_EXIST res["message"] = str(err) res["result"] = "fail" return res try: self.controller.update(args_["item"], **body_) except SQLAlchemyError as err: res["err_code"] = APIStatus.DB_ERROR res["message"] = json.dumps(err.orig.args) res["result"] = "fail" except Exception as err: res["err_code"] = APIStatus.UNDEFINED res["message"] = str(err) res["result"] = "fail" else: res["err_code"] = APIStatus.SUCCESS res["err_code"] = APIStatus.SUCCESS return res
def search(self, body_, current_user): res = AppSetting.general_result() res["request_info"] = self.request_info if not Permission.check_user_role(self.view_roles, current_user["roles"]): res["err_code"] = APIStatus.ROLE_FORBIDDEN res["message"] = "user role is forbidden: {}".format( current_user["username"]) res["result"] = "fail" return res try: res["data"] = self.controller.search(**body_) or [] except SQLAlchemyError as err: # print(err.orig.args) res["err_code"] = APIStatus.DB_ERROR res["message"] = json.dumps(err.orig.args) res["result"] = "fail" except Exception as err: res["err_code"] = APIStatus.UNDEFINED res["message"] = str(err) res["result"] = "fail" else: res["err_code"] = APIStatus.SUCCESS return res
def manage(request, mode, action): data_str = request.POST.get("data", None) formset_id = request.COOKIES.get("formset_id", None) instance_id = request.POST.get("id", request.GET.get("id", None)) data = None # If in the "edit" mode, account_obj contains either a user or a group object # Otherwise the object is None account_obj = None """ If data is send, write this data in cache and follow the following steps accordingly. Otherwise, if it's a step back return the cached data. In any other case it should be the first request in a formset, so return an empty form. """ if data_str: # The user is submitting the form. Trying to deserialize data first. try: data = json.loads(data_str) except: # Damn... returng a bad request error log(6, "accounts_app - account add", "Failed to serialize data string: %s" % data_str) return HttpResponseBadRequest() # Let's dig out the previously recorded data from the cache. formset = cache.get(formset_id) # If the request uses POST method, apperently the user is submiting the form if request.method == "POST": if formset: step = formset["step"] object = formset["object"] # Fetching an object from the DB if instance_id and action == "edit": if object == "user": class_obj = WenixUser else: class_obj = WenixGroup account_obj = class_obj.objects.get(pk=instance_id) if data: # Get the form and check wether the submitted data valid or not. form = get_form(object.title(), action, step)(data) if not form.is_valid(): print data print form return HttpResponse(json.dumps({"ok": 0,"errors": get_errors(form, data)}), mimetype="application/json") # Update formset. All data in the following lines could be reached # only with the formset. formset["data"].update(data) """ If it's the last step in a formset we don't need to return the next step, but rather we return the result of the user/group creation. """ if object == "user" and step == 3: u_perm_obj = Permission(formset["data"]["permissions"]) perm_obj = Permission(request.user.merged_permissions()) groups = WenixGroup.objects.in_bulk(formset["data"]["groups"]).values() g_perm_obj = Permission() for group in groups: g_perm_obj.merge(group.permissions) if u_perm_obj >= g_perm_obj and u_perm_obj <= perm_obj: """ Priviliges check has passed. We have nothing to do but to create or change the user. We don't want redundancy, therefore the common attributes will be fetched here. """ # User permissions first permissions = u_perm_obj.dissect(g_perm_obj.permissions) if action == "add": new_user = WenixUser.objects.create(username=formset["data"]["username"]) # Saving general information about the user for key in ("first_name", "last_name", "email", "permissions"): setattr(new_user, key, formset["data"][key]) # Changing the user's membership new_user.groups = groups # We need to store a clean user password in order for # other modules to be aware of it new_user.password = formset["data"]["password"] # Invoking a method to notify all modules about the new user WenixUser.objects.on_create(new_user) # Setting crypted password and saving the user new_user.set_password(formset["data"]['password']) new_user.save() message = _("A new user '%(username)s' has been created") % {"username": new_user.username} else: # action == "edit" account_obj.save() # Saving general information about the user for key in ("first_name", "last_name", "email", "permissions"): setattr(account_obj, key, formset["data"][key]) # Resetting the user's password if needed if formset["data"]['password']: account_obj.set_password(formset["data"]['password']) # Changing the user's membership account_obj.groups = groups account_obj.save() # Invoking a method to notify all modules about the change WenixUser.objects.on_edit(account_obj, formset["data"]) message = _("The user '%(username)s' has been changed") % {"username": account_obj.username} response = HttpResponse(json.dumps({"ok": 1,"message": message})) response.delete_cookie("formset_id") return response else: """ It turns out as if the user created another user with higher priviliges. That breaks the rules, therefore access should be denied. """ log(5, "accounts_app - account add", "Permission denied for user '%s' creating another user" % request.user.username) return HttpResponse(json.dumps({"ok": 1, "message": _("Access denied")})) elif object == "group" and step == 2: g_perm_obj = Permission(formset["data"]["permissions"]) perm_obj = Permission(request.user.merged_permissions()) if g_perm_obj <= perm_obj: # Fetching users to be included in the group users = WenixUser.objects.in_bulk(formset["data"]["users"] or []).values() """ Priviliges check has passed. We have nothing to do but to create or change the group. """ if action == "add": # We are going to create a new group. group = WenixGroup.objects.create(name=formset["data"]["name"], permissions=g_perm_obj.permissions) # The new members of the group should have their priviliges updated [user.groups.add(group) for user in users] WenixGroup.objects.on_create(group) message = _("A new group '%(name)s' has been created") % {"name": formset["data"]["name"]} else: # action == "edit" # We are going to change a group. group = account_obj # Reseting users's permissions so they can form again # At the same time if a user was in the MultipleChoice # field remove his membership from the group choice_ids = dict(id_and_name_to_dict(request.user, mode, "user")).keys() old_group_users = WenixUser.objects.filter(groups__name=group.name) for u in old_group_users: #cache.delete(CACHE_KEY_UGRPERM % u.username) #cache.delete(CACHE_KEY_USERPERM % u.username) if str(u.id) in choice_ids: u.groups.remove(group) # Contructing a new dictionary with old_dat to pass with "on_edit" method old_data = {"permissions": group.permissions, "users": old_group_users} group.permissions = g_perm_obj.permissions group.save() # We're going to add users to the group for user in users: user.groups.add(group) #if not user in old_group_users: # cache.delete(CACHE_KEY_UGRPERM % user.username) # cache.delete(CACHE_KEY_USERPERM % user.username) # On edit method has three arguments: user, object_being_changed and new_data WenixGroup.objects.on_edit(request.user, group, old_data) message = _("The priviliges for the group '%(name)s' have been saved") % {"name": group.name} response = HttpResponse(json.dumps({"ok": 1,"message": message})) response.delete_cookie("formset_id") return response else: """ It turns out as if the user created another group with higher priviliges. That breaks the rules, therefore access should be denied. """ log(6, "accounts_app - account add", "Permission denied for user '%s' creating another group" % request.user.username) return HttpResponse(json.dumps({"ok": 1,"message": _("Access denied")})) formset["step"] += 1 else: if formset["step"] > 1: formset["step"] -= 1 else: formset["step"] = 1 step = formset["step"] form = get_form(object.title(), action, step) # Generating the next form according to the step if object == "user": if step == 1: new_form = form(initial=formset["data"]) elif step == 2: """ We need to initialize group list here. At the same time we can't list groups the user is not a memeber of if she's in the "group" mode. That's why we use "id_and_name_to_dict" function to generate the list. """ new_form = form(initial=formset['data']) new_form["groups"].field.choices = id_and_name_to_dict(request.user, mode, "group") elif step == 3: # Generating permissions groups = WenixGroup.objects.in_bulk(data["groups"]) perm_obj = Permission(request.user.merged_permissions()) g_perm_obj = Permission() for g in groups: g_perm_obj.merge(groups[g].permissions) if action == "add": new_form = {"permissions": perm_obj.render(g_perm_obj.permissions)} else: # action == "edit" u_perm_obj = Permission(account_obj.permissions) u_perm_obj.merge(g_perm_obj.permissions) new_form = {"permissions": perm_obj.render(g_perm_obj.permissions, u_perm_obj.permissions)} else: # Unrecognised step log(6, "accounts_app - account add", "Unknown step: %s" % step) return HttpResponseBadRequest() elif object == "group": if step == 1: new_form = form(initial=formset["data"]) new_form["users"].field.choices = id_and_name_to_dict(request.user, mode, "user") elif step == 2: # Generating permissions perm_obj = Permission(request.user.merged_permissions()) if action == "add": new_form = {"permissions": perm_obj.render()} else: # action == "edit" g_perm_obj = Permission(WenixGroup.objects.get(pk=instance_id).permissions) new_form = {"permissions": perm_obj.render({}, g_perm_obj.permissions)} else: # Unrecognised step log(6, "accounts_app - account add", "Unknown step: %s" % step) return HttpResponseBadRequest() template = get_template(TEMPLATE_FORM_PATH % object) cache.set(formset_id, formset) context = Context({"form": new_form, "step": formset["step"], "action": action, "object": account_obj}) return HttpResponse(json.dumps({"ok": 1, "html": template.render(context)}), mimetype="application/json") # No formset is found. Therefore, we conclude this is the first step. object = request.POST.get("object", request.GET.get("object", "")) if not object in ("user", "group"): log(3, "accounts_app - account add", "An alien object type '%s' has been spotted" % object) return HttpResponseBadRequest() # Create a new formset cache.delete(formset_id) formset_id = gen_formset_id(CACHE_FORMSET[action], object) form_obj = get_form(object, action, 1) if action == "add": data = {} form = form_obj() else: # action == "edit" if object == "user": account_obj = WenixUser.objects.get(pk=instance_id) data = {"groups": map(lambda x: str(int(x)), account_obj.groups.all().values_list("id", flat=True))} form = form_obj(instance=account_obj) else: # object == "group" account_obj = WenixGroup.objects.get(pk=instance_id) data = {"users": map(lambda x: str(int(x)), WenixUser.objects.filter(groups__name=account_obj.name).values_list("id", flat=True))} form = form_obj(initial=data) # An ugly way to initialize users list if object == "group": form["users"].field.choices = id_and_name_to_dict(request.user, mode, "user") cache.set(formset_id, {"object": object, "step": 1, "data": data}) response = render_to_response(TEMPLATE_FORM_PATH % object, {"form": form, "step": 1, "action": action, "object": account_obj}) response.set_cookie("formset_id", formset_id, FORMSET_ID_MAXAGE) return response
def post(self, body_, current_user): """ 创建新用户 """ res = AppSetting.general_result() res["request_info"] = self.request_info if not Permission.check_user_role(self.edit_roles, current_user["roles"]): res["err_code"] = APIStatus.ROLE_FORBIDDEN res["message"] = "user role is forbidden: {}".format( current_user["username"]) res["result"] = "fail" return res # print(body_) for field in self.fields_require: if field not in body_: res["err_code"] = APIStatus.FIELD_LACK res["message"] = "field lack: {}".format(field) res["result"] = "fail" return res for field in list(body_.keys()): if field not in self.fields_border: body_.pop(field) try: self._check_unique_field(body_, self.controller.get_model().unique_list) except Exception as err: res["err_code"] = APIStatus.ALREADY_EXIST res["message"] = str(err) res["result"] = "fail" return res try: key_word = self.controller.get_model().key_word table_name = self.controller.get_model().table_name search_res = self.controller.search_keyword_on_create( key_word=body_[key_word]) if search_res: if search_res["deleted"] is None or search_res["deleted"] == "": res["err_code"] = APIStatus.ALREADY_EXIST res["message"] = "{table_name} [{key_word}] is already exist".format( table_name=table_name, key_word=body_[key_word]) res["result"] = "fail" return res else: uid = search_res["uid"] body_["deleted"] = None self.controller.update(uid, **body_) res["data"] = {"uid": uid} else: res["data"] = {"uid": self.controller.create(**body_)} except SQLAlchemyError as err: res["err_code"] = APIStatus.DB_ERROR res["message"] = json.dumps(err.orig.args) res["result"] = "fail" except Exception as err: res["err_code"] = APIStatus.UNDEFINED res["message"] = str(err) res["result"] = "fail" else: res["err_code"] = APIStatus.SUCCESS return res