Beispiel #1
0
def edit(request, entry_id):
    entry, error = get_obj_with_check_perm(request.user, Entry, entry_id,
                                           ACLType.Writable)
    if error:
        return error

    # prevent to show edit page under the creating processing
    if entry.get_status(Entry.STATUS_CREATING):
        return HttpResponse("Target entry is now under processing", status=400)

    if not entry.is_active:
        return _redirect_restore_entry(entry)

    context = {
        "entry": entry,
        "groups": Group.objects.filter(is_active=True),
        "attributes": entry.get_available_attrs(request.user,
                                                ACLType.Writable),
        "form_url": "/entry/do_edit/%s" % entry.id,
        "redirect_url": "/entry/show/%s" % entry.id,
    }

    if custom_view.is_custom("edit_entry", entry.schema.name):
        # show custom view
        return custom_view.call_custom("edit_entry", entry.schema.name,
                                       request, request.user, entry, context)
    else:
        return render(request, "edit_entry.html", context)
Beispiel #2
0
 def test_get_obj_with_check_perm(self):
     for obj in [self.entity, self.entityattr, self.entry, self.attr]:
         target_obj, error = get_obj_with_check_perm(
             self.user, obj.__class__, obj.id, ACLType.Full
         )
         self.assertEqual(target_obj, obj)
         self.assertIsNone(error)
Beispiel #3
0
def do_restore(request, entry_id, recv_data):
    entry, error = get_obj_with_check_perm(request.user, Entry, entry_id,
                                           ACLType.Full)
    if error:
        return error

    if entry.is_active:
        return JsonResponse(
            data={"msg": "Failed to get entry from specified parameter"},
            status=400)

    # checks that a same name entry corresponding to the entity is existed, or not.
    dup_entry = Entry.objects.filter(
        schema=entry.schema.id,
        name=re.sub(r"_deleted_[0-9_]*$", "", entry.name),
        is_active=True,
    ).first()
    if dup_entry:
        return JsonResponse(
            data={
                "msg": "",
                "entry_id": dup_entry.id,
                "entry_name": dup_entry.name
            },
            status=400,
        )

    entry.set_status(Entry.STATUS_CREATING)

    # Create a new job to restore deleted entry and run it
    job = Job.new_restore(request.user, entry)
    job.run()

    return HttpResponse("Success to queue a request to restore an entry")
Beispiel #4
0
def index(request, obj_id):
    aclbase_obj, error = get_obj_with_check_perm(request.user, ACLBase, obj_id, ACLType.Full)
    if error:
        return error
    target_obj = aclbase_obj.get_subclass_object()

    # Some type of objects needs object that refers target_obj (e.g. Attribute)
    # for showing breadcrumb navigation.
    parent_obj = None
    try:
        if isinstance(target_obj, Attribute):
            parent_obj = target_obj.parent_entry
        elif isinstance(target_obj, EntityAttr):
            parent_obj = target_obj.parent_entity
    except StopIteration:
        Logger.warning("failed to get related parent object")

    context = {
        "object": target_obj,
        "parent": parent_obj,
        "acltypes": [{"id": x.id, "name": x.label} for x in ACLType.all()],
        "roles": [
            {
                "id": x.id,
                "name": x.name,
                "description": x.description,
                "current_permission": x.get_current_permission(target_obj),
            }
            for x in Role.objects.filter(is_active=True)
            if request.user.is_superuser or x.is_belonged_to(request.user)
        ],
    }
    return render(request, "edit_acl.html", context)
Beispiel #5
0
def do_edit(request, entity_id, recv_data):
    entity, error = get_obj_with_check_perm(request.user, Entity, entity_id, ACLType.Writable)
    if error:
        return error

    # validation checks
    for attr in recv_data["attrs"]:
        # formalize recv_data format
        if "ref_ids" not in attr:
            attr["ref_ids"] = []

        if int(attr["type"]) & AttrTypeValue["object"] and not attr["ref_ids"]:
            return HttpResponse("Need to specify enabled referral ids", status=400)

        if any([not Entity.objects.filter(id=x).exists() for x in attr["ref_ids"]]):
            return HttpResponse("Specified referral is invalid", status=400)

    # duplication checks
    counter = collections.Counter(
        [
            attr["name"]
            for attr in recv_data["attrs"]
            if "deleted" not in attr or not attr["deleted"]
        ]
    )
    if len([v for v, count in counter.items() if count > 1]):
        return HttpResponse("Duplicated attribute names are not allowed", status=400)

    # prevent to show edit page under the processing
    if entity.get_status(Entity.STATUS_EDITING):
        return HttpResponse("Target entity is now under processing", status=400)

    if custom_view.is_custom("edit_entity"):
        resp = custom_view.call_custom(
            "edit_entity", None, entity, recv_data["name"], recv_data["attrs"]
        )
        if resp:
            return resp

    # update status parameters
    if recv_data["is_toplevel"]:
        entity.set_status(Entity.STATUS_TOP_LEVEL)
    else:
        entity.del_status(Entity.STATUS_TOP_LEVEL)

    # update entity metatada informations to new ones
    entity.set_status(Entity.STATUS_EDITING)

    # Create a new job to edit entity and run it
    job = Job.new_edit_entity(request.user, entity, params=recv_data)
    job.run()

    new_name = recv_data["name"]
    return JsonResponse(
        {
            "entity_id": entity.id,
            "entity_name": new_name,
            "msg": 'Success to schedule to update Entity "%s"' % new_name,
        }
    )
Beispiel #6
0
def do_delete(request, entity_id, recv_data):
    entity, error = get_obj_with_check_perm(request.user, Entity, entity_id, ACLType.Full)
    if error:
        return error

    if not entity.is_active:
        return HttpResponse("Target entity is now under processing", status=400)

    if Entry.objects.filter(schema=entity, is_active=True).exists():
        return HttpResponse(
            "cannot delete Entity because one or more Entries are not deleted",
            status=400,
        )

    if custom_view.is_custom("delete_entity"):
        resp = custom_view.call_custom("delete_entity", None, entity)
        if resp:
            return resp

    ret = {}
    # save deleting target name before do it
    ret["name"] = entity.name

    # set deleted flag in advance because deleting processing takes long time
    entity.is_active = False
    entity.save(update_fields=["is_active"])

    # Create a new job to delete entry and run it
    job = Job.new_delete_entity(request.user, entity)
    job.run()

    return JsonResponse(ret)
Beispiel #7
0
def copy(request, entry_id):
    entry, error = get_obj_with_check_perm(request.user, Entry, entry_id,
                                           ACLType.Writable)
    if error:
        return error

    # prevent to show edit page under the creating processing
    if entry.get_status(Entry.STATUS_CREATING) or entry.get_status(
            Entry.STATUS_EDITING):
        return HttpResponse("Target entry is now under processing", status=400)

    if not entry.is_active:
        return _redirect_restore_entry(entry)

    context = {
        "form_url": "/entry/do_copy/%s" % entry.id,
        "redirect_url": "/entry/%s" % entry.schema.id,
        "entry": entry,
    }

    if custom_view.is_custom("copy_entry", entry.schema.name):
        return custom_view.call_custom("copy_entry", entry.schema.name,
                                       request, request.user, entry, context)

    return render(request, "copy_entry.html", context)
Beispiel #8
0
def edit(request, entity_id):
    entity, error = get_obj_with_check_perm(request.user, Entity, entity_id, ACLType.Writable)
    if error:
        return error

    # when an entity in referral attribute is deleted
    # user should be able to select new entity or keep it unchanged
    # candidate entites for referral are:
    # - active(not deleted) entity
    # - current value of any attributes even if the entity has been deleted
    context = {
        "entity": entity,
        "attr_types": AttrTypes,
        "attributes": [
            {
                "id": x.id,
                "name": x.name,
                "type": x.type,
                "is_mandatory": x.is_mandatory,
                "is_delete_in_chain": x.is_delete_in_chain,
                "referrals": x.referral.all(),
            }
            for x in entity.attrs.filter(is_active=True).order_by("index")
            if request.user.has_permission(x, ACLType.Writable)
        ],
    }
    return render(request, "edit_entity.html", context)
Beispiel #9
0
 def test_get_obj_with_check_perm_with_invalid_param(self):
     target_obj, error = get_obj_with_check_perm(self.user, Entry,
                                                 self.entity.id,
                                                 ACLType.Full)
     self.assertIsNone(target_obj)
     self.assertEqual(error.content,
                      b"Failed to get entity of specified id")
     self.assertEqual(error.status_code, 400)
Beispiel #10
0
    def test_get_obj_with_check_perm_without_permission(self):
        self.entry.is_public = False
        self.entry.save()

        target_obj, error = get_obj_with_check_perm(self.user, Entry, self.entry.id, ACLType.Full)
        self.assertIsNone(target_obj)
        self.assertEqual(error.content, b"You don't have permission to access this object")
        self.assertEqual(error.status_code, 400)
Beispiel #11
0
def do_import_data(request, entity_id, context):
    user: User = request.user
    entity: Entity
    entity, error = get_obj_with_check_perm(user, Entity, entity_id,
                                            ACLType.Writable)
    if error:
        return error
    if not entity.is_active:
        return HttpResponse("Failed to get entity of specified id", status=400)

    try:
        data = yaml.load(context, Loader=yaml.FullLoader)
    except yaml.parser.ParserError:
        return HttpResponse("Couldn't parse uploaded file", status=400)
    except ValueError as e:
        return HttpResponse("Invalid value is found: %s" % e, status=400)
    except yaml.scanner.ScannerError:
        return HttpResponse("Couldn't scan uploaded file", status=400)
    except Exception as e:
        return HttpResponse("Unknown exception: %s" % e, status=500)

    if not Entry.is_importable_data(data):
        return HttpResponse(
            "Uploaded file has invalid data structure to import", status=400)

    for entity_name in data.keys():
        import_entity: Entity = Entity.objects.filter(name=entity_name,
                                                      is_active=True).first()
        if not import_entity:
            return HttpResponse("Specified entity does not exist (%s)" %
                                entity_name,
                                status=400)
        if not user.has_permission(import_entity, ACLType.Writable):
            return HttpResponse("You don't have permission to access (%s)" %
                                entity_name,
                                status=400)

        import_data = data[entity_name]

        if custom_view.is_custom("import_entry", entity_name):
            # import custom view
            import_data, err_msg = custom_view.call_custom(
                "import_entry", entity_name, user, import_entity, import_data)

            # If custom_view returns available response this returns it to user,
            # or continues default processing.
            if err_msg:
                return HttpResponse(err_msg, status=400)

        # create job to import data to create or update entries and run it
        job = Job.new_import(user,
                             import_entity,
                             text="Preparing to import data",
                             params=import_data)
        job.run()

    return HttpResponseSeeOther("/entry/%s/" % entity_id)
Beispiel #12
0
def do_copy(request, entry_id, recv_data):
    entry, error = get_obj_with_check_perm(request.user, Entry, entry_id,
                                           ACLType.Full)
    if error:
        return error

    ret = []
    params = {
        "new_name_list": [],
        "post_data": recv_data,
    }
    for new_name in [x for x in recv_data["entries"].split("\n") if x]:
        if (new_name in params["new_name_list"] or Entry.objects.filter(
                schema=entry.schema, name=new_name).exists()):
            ret.append({
                "status":
                "fail",
                "msg":
                "A same named entry (%s) already exists" % new_name,
            })
            continue

        if custom_view.is_custom("do_copy_entry", entry.schema.name):
            (is_continue, status, msg) = custom_view.call_custom(
                "do_copy_entry",
                entry.schema.name,
                request,
                entry,
                recv_data,
                request.user,
                new_name,
            )
            if not is_continue:
                ret.append({
                    "status": "success" if status else "fail",
                    "msg": msg,
                })
                continue

        params["new_name_list"].append(new_name)
        ret.append({
            "status": "success",
            "msg": "Success to create new entry '%s'" % new_name,
        })

    # if there is no entry to copy, do not create a job.
    if params["new_name_list"]:
        # make a new job to copy entry and run it
        job = Job.new_copy(request.user,
                           entry,
                           text="Preparing to copy entry",
                           params=params)
        job.run()

    return JsonResponse({"results": ret})
Beispiel #13
0
def do_edit(request, entry_id, recv_data):
    entry, error = get_obj_with_check_perm(request.user, Entry, entry_id,
                                           ACLType.Writable)
    if error:
        return error

    # checks that a same name entry corresponding to the entity is existed.
    query = Q(schema=entry.schema,
              name=recv_data["entry_name"]) & ~Q(id=entry.id)
    if Entry.objects.filter(query).exists():
        return HttpResponse("Duplicate name entry is existed", status=400)

    # validate contexts of each attributes
    err = _validate_input(recv_data, entry)
    if err:
        return err

    if entry.get_status(Entry.STATUS_CREATING):
        return HttpResponse("Target entry is now under processing", status=400)

    if custom_view.is_custom("do_edit_entry", entry.schema.name):
        # resp is HttpReponse instance or its subclass (e.g. JsonResponse)
        resp = custom_view.call_custom("do_edit_entry", entry.schema.name,
                                       request, recv_data, request.user, entry)
        if resp:
            return resp

    # update name of Entry object. If name would be updated, the elasticsearch data of entries that
    # refers this entry also be updated by creating REGISTERED_REFERRALS task.
    job_register_referrals = None
    if entry.name != recv_data["entry_name"]:
        job_register_referrals = Job.new_register_referrals(
            request.user, entry)

    entry.name = recv_data["entry_name"]
    entry.save(update_fields=["name"])

    # set flags that indicates target entry is under processing
    entry.set_status(Entry.STATUS_EDITING)

    # Create new jobs to edit entry and notify it to registered webhook endpoint if it's necessary
    job_edit_entry = Job.new_edit(request.user, entry, params=recv_data)
    job_edit_entry.run()

    # running job of re-register referrals because of chaning entry's name
    if job_register_referrals:
        job_register_referrals.dependent_job = job_edit_entry
        job_register_referrals.run()

    return JsonResponse({
        "entry_id": entry.id,
        "entry_name": entry.name,
    })
Beispiel #14
0
def list_webhook(request, entity_id):
    entity, error = get_obj_with_check_perm(request.user, Entity, entity_id, ACLType.Full)
    if error:
        return error

    return render(
        request,
        "list_webhooks.html",
        {
            "entity": entity,
            "webhooks": entity.webhooks.all(),
        },
    )
Beispiel #15
0
def index(request, entity_id):
    entity, error = get_obj_with_check_perm(request.user, Entity, entity_id,
                                            ACLType.Readable)
    if error:
        return error

    page = request.GET.get("page", 1)
    keyword = request.GET.get("keyword", None)

    if custom_view.is_custom("list_entry_without_context", entity.name):
        # show custom view without context
        resp = custom_view.call_custom("list_entry_without_context",
                                       entity.name, request, entity)
        if resp:
            return resp

    if keyword:
        name_pattern = prepend_escape_character(
            CONFIG.ESCAPE_CHARACTERS_ENTRY_LIST, keyword)
        entries = Entry.objects.order_by("name").filter(
            schema=entity, is_active=True, name__iregex=name_pattern)
    else:
        entries = Entry.objects.order_by("name").filter(schema=entity,
                                                        is_active=True)

    p = Paginator(entries, CONFIG.MAX_LIST_ENTRIES)
    try:
        page_obj = p.page(page)
    except PageNotAnInteger:
        return HttpResponse("Invalid page number. It must be unsigned integer",
                            status=400)
    except EmptyPage:
        return HttpResponse(
            "Invalid page number. The page doesn't have anything", status=400)

    context = {
        "entity": entity,
        "keyword": keyword,
        "page_obj": page_obj,
    }

    if custom_view.is_custom("list_entry", entity.name):
        # list custom view
        return custom_view.call_custom("list_entry", entity.name, request,
                                       entity, context)
    else:
        # list ordinal view
        return render(request, "list_entry.html", context)
Beispiel #16
0
def do_delete(request, entry_id, recv_data):
    entry, error = get_obj_with_check_perm(request.user, Entry, entry_id,
                                           ACLType.Full)
    if error:
        return error

    if custom_view.is_custom("do_delete_entry", entry.schema.name):
        # do_delete custom view
        resp = custom_view.call_custom("do_delete_entry", entry.schema.name,
                                       request, request.user, entry)

        # If custom_view returns available response this returns it to user,
        # or continues default processing.
        if resp:
            return resp

    # set deleted flag in advance because deleting processing taks long time
    entry.is_active = False
    entry.save(update_fields=["is_active"])

    ret = {}
    # save deleting Entry name before do it
    ret["name"] = entry.name

    # register operation History for deleting entry
    request.user.seth_entry_del(entry)

    # Create a new job to delete entry and run it
    job_delete_entry = Job.new_delete(request.user, entry)
    job_notify_event = Job.new_notify_delete_entry(request.user, entry)

    # This prioritizes notifying job rather than deleting entry
    if job_delete_entry.dependent_job:
        job_notify_event.dependent_job = job_delete_entry.dependent_job

    job_notify_event.save(update_fields=["dependent_job"])
    job_notify_event.run()

    # This update dependent job of deleting entry job
    job_delete_entry.dependent_job = job_notify_event
    job_delete_entry.save(update_fields=["dependent_job"])

    job_delete_entry.run()

    return JsonResponse(ret)
Beispiel #17
0
def create(request, entity_id):
    entity, error = get_obj_with_check_perm(request.user, Entity, entity_id,
                                            ACLType.Writable)
    if error:
        return error

    if custom_view.is_custom("create_entry_without_context", entity.name):
        # show custom view
        return custom_view.call_custom("create_entry_without_context",
                                       entity.name, request, request.user,
                                       entity)

    context = {
        "entity":
        entity,
        "form_url":
        "/entry/do_create/%s/" % entity.id,
        "redirect_url":
        "/entry/%s" % entity.id,
        "groups":
        Group.objects.filter(is_active=True),
        "attributes": [{
            "entity_attr_id":
            x.id,
            "id":
            x.id,
            "type":
            x.type,
            "name":
            x.name,
            "is_mandatory":
            x.is_mandatory,
            "is_readble":
            True
            if request.user.has_permission(x, ACLType.Writable) else False,
        } for x in entity.attrs.filter(is_active=True).order_by("index")],
    }

    if custom_view.is_custom("create_entry", entity.name):
        # show custom view
        return custom_view.call_custom("create_entry", entity.name, request,
                                       request.user, entity, context)
    else:
        return render(request, "create_entry.html", context)
Beispiel #18
0
def history(request, entry_id):
    entry, error = get_obj_with_check_perm(request.user, Entry, entry_id,
                                           ACLType.Readable)
    if error:
        return error

    if entry.get_status(Entry.STATUS_CREATING):
        return HttpResponse("Target entry is now under processing", status=400)

    if not entry.is_active:
        return _redirect_restore_entry(entry)

    context = {
        "entry": entry,
        "value_history": entry.get_value_history(request.user),
        "history_count": CONFIG.MAX_HISTORY_COUNT,
    }

    return render(request, "show_entry_history.html", context)
Beispiel #19
0
def restore(request, entity_id):
    entity, error = get_obj_with_check_perm(request.user, Entity, entity_id,
                                            ACLType.Full)
    if error:
        return error

    page = request.GET.get("page", 1)
    keyword = request.GET.get("keyword", None)

    # get all deleted entries that correspond to the entity, the specififcation of
    # 'status=0' is necessary to prevent getting entries that were under processing.
    if keyword:
        name_pattern = prepend_escape_character(
            CONFIG.ESCAPE_CHARACTERS_ENTRY_LIST, keyword)
        entries = Entry.objects.filter(
            schema=entity,
            status=0,
            is_active=False,
            name__iregex=name_pattern).order_by("-updated_time")
    else:
        entries = Entry.objects.filter(
            schema=entity, status=0, is_active=False).order_by("-updated_time")

    p = Paginator(entries, CONFIG.MAX_LIST_ENTRIES)
    try:
        page_obj = p.page(page)
    except PageNotAnInteger:
        return HttpResponse("Invalid page number. It must be unsigned integer",
                            status=400)
    except EmptyPage:
        return HttpResponse(
            "Invalid page number. The page doesn't have anything", status=400)

    return render(
        request,
        "list_deleted_entry.html",
        {
            "entity": entity,
            "keyword": keyword,
            "page_obj": page_obj,
        },
    )
Beispiel #20
0
def refer(request, entry_id):
    entry, error = get_obj_with_check_perm(request.user, Entry, entry_id,
                                           ACLType.Readable)
    if error:
        return error

    if entry.get_status(Entry.STATUS_CREATING):
        return HttpResponse("Target entry is now under processing", status=400)

    if not entry.is_active:
        return _redirect_restore_entry(entry)

    # get referred entries and count of them
    referred_objects = entry.get_referred_objects()

    context = {
        "entry": entry,
        "referred_objects": referred_objects[0:CONFIG.MAX_LIST_REFERRALS],
        "referred_total": referred_objects.count(),
    }
    return render(request, "show_entry_refer.html", context)
Beispiel #21
0
def do_create(request, entity_id, recv_data):
    # get objects to be referred in the following processing
    entity, error = get_obj_with_check_perm(request.user, Entity, entity_id,
                                            ACLType.Writable)
    if error:
        return error

    # checks that a same name entry corresponding to the entity is existed, or not.
    if Entry.objects.filter(schema=entity_id,
                            name=recv_data["entry_name"]).exists():
        return HttpResponse("Duplicate name entry is existed", status=400)

    # validate contexts of each attributes
    err = _validate_input(recv_data, entity)
    if err:
        return err

    if custom_view.is_custom("do_create_entry", entity.name):
        # resp is HttpReponse instance or its subclass (e.g. JsonResponse)
        resp = custom_view.call_custom("do_create_entry", entity.name, request,
                                       recv_data, request.user, entity)
        if resp:
            return resp

    # Create a new Entry object
    entry = Entry.objects.create(
        name=recv_data["entry_name"],
        created_user=request.user,
        schema=entity,
        status=Entry.STATUS_CREATING,
    )

    # Create a new job to create entry and run it
    job_create_entry = Job.new_create(request.user, entry, params=recv_data)
    job_create_entry.run()

    return JsonResponse({
        "entry_id": entry.id,
        "entry_name": entry.name,
    })
Beispiel #22
0
def show(request, entry_id):
    entry, error = get_obj_with_check_perm(request.user, Entry, entry_id,
                                           ACLType.Readable)
    if error:
        return error

    if entry.get_status(Entry.STATUS_CREATING):
        return HttpResponse("Target entry is now under processing", status=400)

    if not entry.is_active:
        return _redirect_restore_entry(entry)

    context = {
        "entry": entry,
        "attributes": entry.get_available_attrs(request.user),
    }

    if custom_view.is_custom("show_entry", entry.schema.name):
        # show custom view
        return custom_view.call_custom("show_entry", entry.schema.name,
                                       request, request.user, entry, context)
    else:
        # show ordinal view
        return render(request, "show_entry.html", context)
Beispiel #23
0
def set_webhook(request, entity_id, recv_data):
    entity, error = get_obj_with_check_perm(request.user, Entity, entity_id,
                                            ACLType.Full)
    if error:
        return error

    if not entity.is_active:
        return JsonResponse({"msg": "There is no entity for setting"},
                            status=400)

    # check specified parameters are valid
    validate = URLValidator()
    try:
        # This checks webhook_url is valid HTTP URL
        validate(recv_data["webhook_url"])

    except ValidationError:
        return HttpResponse("Specified URL is invalid", status=400)

    if "id" in recv_data:
        # get Webhook instance and set values
        webhook = Webhook.objects.filter(id=recv_data["id"]).first()
        if not webhook:
            return HttpResponse("Invalid Webhook ID is specified", status=400)

        webhook.url = recv_data["webhook_url"]
        webhook.label = recv_data["label"]
        webhook.headers = recv_data.get("request_headers", [])
        webhook.is_enabled = recv_data["is_enabled"]
    else:
        # create Webhook instance and set values
        webhook = Webhook.objects.create(
            **{
                "url": recv_data["webhook_url"],
                "label": recv_data["label"],
                "headers": recv_data.get("request_headers", []),
                "is_enabled": recv_data["is_enabled"],
            })
        entity.webhooks.add(webhook)

    try:
        resp = requests.post(
            recv_data["webhook_url"], **{
                "headers": {
                    x["header_key"]: x["header_value"]
                    for x in recv_data.get("request_headers", [])
                },
                "data": json.dumps({}),
                "verify": False,
            })

        # The is_verified parameter will be set True,
        # when requests received HTTP 200 from specifying endpoint.
        webhook.is_verified = resp.ok
    except ConnectionError:
        webhook.is_verified = False

    webhook.save()

    return JsonResponse({
        "webhook_id": webhook.id,
        "msg": "Succeded in registering Webhook"
    })