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 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