Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Redesign the permission management for project creation #127

Open
lbergesio opened this issue Apr 12, 2013 · 4 comments
Open

Redesign the permission management for project creation #127

lbergesio opened this issue Apr 12, 2013 · 4 comments

Comments

@lbergesio
Copy link
Member

Modify the permission management of project request in the dashboard to let it create the project automatically with the data sent by the user.

@ghost ghost assigned lbergesio Apr 12, 2013
@CarolinaFernandez
Copy link
Member

I have a little doubt about this:

as for now, the administrator grants the create_project permission through Expedient, when this first project creation request is sent (and the admin approves it). From there onward the user can directly create projects.

Will the user be able to directly create projects after this first approval & project creation by the admin ( this means to keep the permission system almost "as it is" already ) or is it intended that the user has to ask for every project creation ( more interferences for the IM or admin )?

I guess this change is only meant for the first time, to ease the admin work and then leave the user the right to do by itself. Right?

@CarolinaFernandez
Copy link
Member

Done.

The approval/deny of each project will be automatically made when the admin user ticks the corresponding check box. User shall go through this procedure every time he/she wants to request a project, as usual (although it is not the idea used for the permissions granting in the original Stanford's Expedient, which granted the can_create_project permission after the first [approved] request)

The permission & permission management views, along with templates like the permission & confirmation requests were modified. Some are shown, to illustrate the changes and for future reference or whatsoever.

File: expedient/src/python/expedient/clearinghouse/permissionmgmt/views.py

def confirm_requests(request):
    """Confirm the approval of the permission requests."""

    approved_req_ids = request.session.setdefault("approved_req_ids", [])
    delegatable_req_ids = request.session.setdefault("delegatable_req_ids", [])
    denied_req_ids = request.session.setdefault("denied_req_ids", [])

    approved_reqs = []
    for req_id in approved_req_ids:
        req = get_object_or_404(PermissionRequest, id=req_id)
        delegatable = req_id in delegatable_req_ids
        approved_reqs.append((req, delegatable))

    denied_reqs = []
    for req_id in denied_req_ids:
        denied_reqs.append(
            get_object_or_404(PermissionRequest, id=req_id))

    if request.method == "POST":
        # check if confirmed and then do actions.
        if request.POST.get("post", "no") == "yes":
            for req in denied_reqs:
                req.deny()
#                DatedMessage.objects.post_message_to_user(
#                    "Request for permission %s for object %s denied."
#                    % (req.requested_permission.permission.name,
#                       req.requested_permission.target),
#                    user=req.requesting_user,
#                    sender=req.permission_owner,
#                    msg_type=DatedMessage.TYPE_WARNING)

                posted_message = "Request for %s denied." % str(req.requested_permission.target).capitalize()
                if req.requested_permission.permission.name == "can_create_project":
                    # Removes "* Project name: "
                    try:
                        project_name = req.message.split("||")[0].strip()[16:]
                    except:
                        pass
                    posted_message = "Request for project %s creation denied." % project_name
                # -------------------------------------------
                # It is not about permission granting anymore
                # -------------------------------------------
                DatedMessage.objects.post_message_to_user(
                    posted_message,
                    user = req.requesting_user,
                    sender = req.permission_owner,
                    msg_type = DatedMessage.TYPE_WARNING)

            for req, delegate in approved_reqs:
                # --------------------------------------------------------
                # Do NOT grant permission to create projects in the future
                # --------------------------------------------------------
#                req.allow(can_delegate=delegate)
                req.deny()
#                DatedMessage.objects.post_message_to_user(
#                    "Request for permission %s for object %s approved."
#                    % (req.requested_permission.permission.name,
#                       req.requested_permission.target),
#                    user=req.requesting_user,
#                    sender=req.permission_owner,
#                    msg_type=DatedMessage.TYPE_SUCCESS)

                posted_message = "Request for %s approved." % str(req.requested_permission.target).capitalize()
                # ---------------------------------------
                # Project will be created in a direct way
                # ---------------------------------------
                if req.requested_permission.permission.name == "can_create_project":
                    project = Project()
                    project.uuid = uuid.uuid4()
                    try:
                        message = req.message.split("||")
                        # Removes "* Project name: "
                        project.name = message[0].strip()[16:]
                        # Removes "* Project description: "
                        project.description = message[3].strip()[23:]
                        posted_message = "Successfully created project %s." % project.name
                    except:
                        # If some parsing error were to occur, set random name and description
                        import random
                        nonce = str(random.randrange(10000))
                        project.name = "Project_" % nonce
                        project.description = "Description_" % nonce
                        posted_message = "Project %s created, but you might need to edit it." % project.name
                    project.save()
                    create_project_roles(project, req.requesting_user)
                DatedMessage.objects.post_message_to_user(
                    posted_message,
                    user = req.requesting_user,
                    sender = req.permission_owner,
                    msg_type = DatedMessage.TYPE_SUCCESS)

        # After this post we will be done with all this information
        del request.session["approved_req_ids"]
        del request.session["delegatable_req_ids"]
        del request.session["denied_req_ids"]

        return HttpResponseRedirect(reverse("home"))

    else:
        return direct_to_template(
            request=request,
            template=TEMPLATE_PATH+"/confirm_requests.html",
            extra_context={
                "approved_reqs": approved_reqs,
                "denied_reqs": denied_reqs,
            }
        )

File: expedient/src/templates/default/expedient/clearinghouse/permissionmgmt/confirm_requests.html

    {% if approved_reqs %}
    <!--<h2>The following permission requests will be approved:</h2>-->
    <h2>The following requests will be approved:</h2>
        <ul>
                {% for req, delegatable in approved_reqs %}
                <li>
                        <!--Permission
                        <a class="perm_name" id="name_{{ req.id }}" href="#">
                                {{ req.requested_permission.permission.name }}
                        </a>-->
                        {{ req.requested_permission.target|title }}
                        requested by {{ req.requesting_user }} <!--for object
                        {{ req.requested_permission.target }}--> will be granted. <!--to 
                        {{ req.permittee }}. {{ req.permittee }} 
                        {% if delegatable %}<strong>will</strong>{% else %}will
                        <strong>not</strong>{% endif %} be able to further give permission
                        to other objects.-->
                        <!--<div class="tooltip" id="tip_{{ req.id }}">
                                {{ req.requested_permission.permission.description }}
                        </div>-->
                        <a class="perm_name" id="name_{{ req.id }}" href="#">
                            See details
                        </a>
                        <div class="tooltip" id="tip_{{ req.id }}">
                                {{ req.message }}
                        </div>
                </li>
                {% endfor %}
        </ul>
    {% endif %}

    {% if denied_reqs %}
    <!--<h2>The following permission requests will be denied:</h2>-->
    <h2>The following requests will be denied:</h2>
        <ul>
                {% for req in denied_reqs %}
                <li>
                        <!--Permission 
                        <a class="perm_name" id="name_{{ req.id }}" href="#">
                                {{ req.requested_permission.permission.name }}
                        </a>-->
                        {{ req.requested_permission.target|title }}
                        requested by {{ req.requesting_user }} <!--for {{ req.permittee }} to
                        use object
                        {{ req.requested_permission.target }}--> will be denied.
                        <!--<div class="tooltip" id="tip_{{ req.id }}">
                                {{ req.requested_permission.permission.description }}
                        </div>-->
                        <a class="perm_name" id="name_{{ req.id }}" href="#">
                            See details
                        </a>
                        <div class="tooltip" id="tip_{{ req.id }}">
                                {{ req.message }}
                        </div>
                </li>
                {% endfor %}
        </ul>
    {% endif %}

File: expedient/src/templates/default/expedient/clearinghouse/permissionmgmt/request_permission.html

    <!--If you would like to request this permission
    from a user who has the authority to give it to you, select a user
    from the list below and click the "Request" button.-->
    If you would like to exert the action associated to that permission, fill
    the form with appropriate information and click the "Request" button.

@CarolinaFernandez
Copy link
Member

Project creation was modified because there were problems when project already existed.
There is another change also: user will be sent e-mails when projects are approved/denied or if there is some problem accepting these.

File: expedient/src/python/expedient/clearinghouse/permissionmgmt/views.py

def confirm_requests(request):
    """Confirm the approval of the permission requests."""

    approved_req_ids = request.session.setdefault("approved_req_ids", [])
    delegatable_req_ids = request.session.setdefault("delegatable_req_ids", [])
    denied_req_ids = request.session.setdefault("denied_req_ids", [])

    approved_reqs = []
    for req_id in approved_req_ids:
        req = get_object_or_404(PermissionRequest, id=req_id)
        delegatable = req_id in delegatable_req_ids
        approved_reqs.append((req, delegatable))

    denied_reqs = []
    for req_id in denied_req_ids:
        denied_reqs.append(
            get_object_or_404(PermissionRequest, id=req_id))

    if request.method == "POST":
        # check if confirmed and then do actions.
        if request.POST.get("post", "no") == "yes":
            for req in denied_reqs:
                req.deny()
#                DatedMessage.objects.post_message_to_user(
#                    "Request for permission %s for object %s denied."
#                    % (req.requested_permission.permission.name,
#                       req.requested_permission.target),
#                    user=req.requesting_user,
#                    sender=req.permission_owner,
#                    msg_type=DatedMessage.TYPE_WARNING)

                post_message = "Request for %s denied." % str(req.requested_permission.target).capitalize()
                if req.requested_permission.permission.name == "can_create_project":
                    # Removes "* Project name: "
                    try:
                        project_name = req.message.split("||")[0].strip()[16:]
                        post_message = "Request for project %s creation denied." % project_name

                        # Notify requesting user
                        try:
                            send_mail(
                                     settings.EMAIL_SUBJECT_PREFIX + "Denied project request for '%s'" % (project_name),
                                     "Your request for the creation of project '%s' has been denied.\n\n\nYou may want to get in contact with the Island Manager for further details." % project_name,
                                     from_email = settings.DEFAULT_FROM_EMAIL,
                                     recipient_list = [req.requesting_user.email],
                             )
                        except Exception as e:
                            print "[WARNING] User e-mail notification could not be sent. Details: %s" % str(e)

                    except:
                        pass
                # -------------------------------------------
                # It is not about permission granting anymore
                # -------------------------------------------
                # Notify requesting user
                DatedMessage.objects.post_message_to_user(
                    post_message,
                    user = req.requesting_user,
                    sender = req.permission_owner,
                    msg_type = DatedMessage.TYPE_WARNING)

                # Notify user with permission (e.g. root)
                DatedMessage.objects.post_message_to_user(
                    post_message,
                    user = request.user,
                    sender = req.permission_owner,
                    msg_type = DatedMessage.TYPE_WARNING)

            for req, delegate in approved_reqs:
                # --------------------------------------------------------
                # Do NOT grant permission to create projects in the future
                # --------------------------------------------------------
#                req.allow(can_delegate=delegate)
                req.deny()
#                DatedMessage.objects.post_message_to_user(
#                    "Request for permission %s for object %s approved."
#                    % (req.requested_permission.permission.name,
#                       req.requested_permission.target),
#                    user=req.requesting_user,
#                    sender=req.permission_owner,
#                    msg_type=DatedMessage.TYPE_SUCCESS)

                post_message = "Request for %s approved." % str(req.requested_permission.target).capitalize()
                permission_user_post = post_message
                requesting_user_post = post_message
                email_header = post_message
                email_body = "%s." % post_message
                message_type = DatedMessage.TYPE_SUCCESS
                # ---------------------------------------
                # Project will be created in a direct way
                # ---------------------------------------
                if req.requested_permission.permission.name == "can_create_project":
                    project_name = ""
                    try:
                        project = Project()
                        project.uuid = uuid.uuid4()
                        message = req.message.split("||")
                        # Removes "* Project name: "
                        project.name = message[0].strip()[16:]
                        project_name = project.name
                        # Removes "* Project description: "
                        project.description = message[3].strip()[23:]
                        post_message = "Successfully created project %s" % project.name
                        project.save()
                        create_project_roles(project, req.requesting_user)
                        email_header = "Approved project request for '%s'" % project_name
                        email_body = "Your request for the creation of project '%s' has been approved." % project_name
                    except Exception as e:
                        # Any error when creating a project results into:
                            # 1. Denying the petition
                            # 2. Notifying user in their Expedient
                            # 3. Notifying user via e-mail
                        post_message = "Project '%s' could not be created" % project_name
                        permission_user_post = post_message
                        requesting_user_post = post_message

                        # Handle exception text for user
                        if "duplicate entry" in str(e).lower():
                            email_body = "There is already a project with name '%s'. Try using a different name" % project_name
                            requesting_user_post += ". Details: project '%s' already exists" % project_name
                        else:
                            email_body = "There might have been a problem when interpreting the information for project '%s'" % str(project_name)
                        requesting_user_post += ". Contact your Island Manager for further details"

                        # Handle exception text for admin
                        if "Details" not in post_message:
                            permission_user_post = "%s. Details: %s" % (post_message, str(e))

                        message_type = DatedMessage.TYPE_ERROR
                        # Email for requesting user
                        email_header = "Denied project request for '%s'" % project_name
                        email_body = "Your request for the creation of project '%s' has been denied because of the following causes:\n\n%s\n\n\nYou may want to get in contact with the Island Manager for further details." % (project_name, email_body)
                    # Notify requesting user
                    DatedMessage.objects.post_message_to_user(
                        requesting_user_post,
                        user = req.requesting_user,
                        sender = req.permission_owner,
                        msg_type = message_type)

                    try:
                        send_mail(
                                 settings.EMAIL_SUBJECT_PREFIX + email_header,
                                 email_body,
                                 from_email = settings.DEFAULT_FROM_EMAIL,
                                 recipient_list = [req.requesting_user.email],
                         )
                    except Exception as e:
                        print "[WARNING] User e-mail notification could not be sent. Details: %s" % str(e)

                    # Notify user with permission (e.g. root)
                    DatedMessage.objects.post_message_to_user(
                        permission_user_post,
                        user = request.user,
                        sender = req.permission_owner,
                        msg_type = message_type)


        # After this post we will be done with all this information
        del request.session["approved_req_ids"]
        del request.session["delegatable_req_ids"]
        del request.session["denied_req_ids"]

        return HttpResponseRedirect(reverse("home"))

    else:
        return direct_to_template(
            request=request,
            template=TEMPLATE_PATH+"/confirm_requests.html",
            extra_context={
                "approved_reqs": approved_reqs,
                "denied_reqs": denied_reqs,
            }
        )

@CarolinaFernandez
Copy link
Member

Automatic project creation (in file expedient/src/python/expedient/clearinghouse/permissionmgmt/views.py) missed a

project.save()

right after the

create_project_roles(project, user)

method is invoked; in order to link all this LDAP info properly. Otherwise the owner won't be able to access VMs via SSH (because he/she is not permitted in the LDAP's project section). Only when another user is added to the project (and therefore the project instance is saved), will he/she be able to access VMs...


And yet another detail to be taken care of in the future (not an issue, though; but this will remain open) is that code is duplicated with this. It might be good to directly call

create(request)

from the project views (file expedient/src/python/expedient/clearinghouse/project/views.py) and appropriately forge the currently existing request for permissions with the missing fields that the project form (ProjectCreateForm) expects.

CarolinaFernandez added a commit that referenced this issue May 17, 2013
… (save project after granting roles to sync LDAP)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants