barseghyanartur / django-fobi

Form generator/builder application for Django done right: customisable, modular, user- and developer- friendly.
https://pypi.python.org/pypi/django-fobi
484 stars 112 forks source link

django-fobi Dashboard Administrator #228

Closed matacino closed 2 years ago

matacino commented 5 years ago

Hello,

could you describe a way that a "Formular-Administrator" could have an overview and access to the editing of all forms?

As far as I can see it in the source code it seems to be intended, that only the creator can view and edit a form in the backend:

` … obj = entry_model_cls._default_manager \ .select_related('form_entry') \ .get(pk=entry_id, form_entryuserpk=request.user.pk) …

{found it approx. that way in edit_form_element_entry(…); _delete_plugin_entry(…), edit_form_wizard_entry(…) and dashboard(…) in the views.} ` This would could come handy, if more than one person works on and with an form.

barseghyanartur commented 5 years ago

@matacino:

That's correct. One way to solve it is to use class-based-views, but I didn't have time to check/finalize them.

chris-nlnz commented 3 years ago

Hi there,

Just wondering if anything has changed in relation to this, i.e. is there a way to allow multiple users to access/edit forms and wizards other than just the creator?

As it would be very useful for us to be able to do this.

Thanks

barseghyanartur commented 3 years ago

@chris-nlnz:

Not just yet (although I want to get my hands on solving a couple of most-wanted issues like this; matter of time/involvement).

For now, one way to solve it, is to copy-paste the edit form view code to allow making the necessary changes.

Alternatively, what's often done, the target groups could share the same account.

Nowadays, it's possible to impersonate a user (using third party libs like django-impersonate). You could try that as well.

If you have a budget (for boosting development of a certain feature) for wish-lists, drop me an email (check the README). :)

chris-nlnz commented 3 years ago

Thanks for your response, and that's understandable. We will probably use a workaround for now. Thanks for the tips, will explore a bit.

barseghyanartur commented 3 years ago

This could be another app for the workaround: https://github.com/avallbona/Impostor

jgadelange commented 2 years ago

I have a situation where the one user and the imporster workarounds really aren't desired. However it would be fine, if all signed in (staff) users can edit all forms.

Looking at the code I don't see a quick way to easily add such a feature. Is there any timeline on this feature?

matacino commented 2 years ago

Hi I am still working with version 0.15 because a while ago I added a user-group-wise editable workflow, changing a few places:

starting at line 150 in src/fobi/views/function_based.py:

def _delete_plugin_entry(request,
                         entry_id,
                         entry_model_cls,
                         get_user_plugin_uids_func,
                         message,
                         html_anchor):
    """Abstract delete entry.

    :param django.http.HttpRequest request:
    :param int entry_id:
    :param fobi.models.AbstractPluginEntry entry_model_cls: Subclass of
        ``fobi.models.AbstractPluginEntry``.
    :param callable get_user_plugin_uids_func:
    :param str message:
    :return django.http.HttpResponse:
    """
    try:
        req_user_gruppe = request.user.groups.values_list("pk", flat=True)
        if request.user.is_staff==True:
            obj = entry_model_cls._default_manager \
                             .select_related('form_entry') \
                             .get(pk=entry_id,
                                  form_entry__work_user_group__pk__in=req_user_gruppe)
        else:
            obj = entry_model_cls._default_manager \
                             .select_related('form_entry') \
                             .get(pk=entry_id,
                                  form_entry__user__pk=request.user.pk)
    except ObjectDoesNotExist as err:
        raise Http404(
            ugettext("{0} not found.").format(
                entry_model_cls._meta.verbose_name
            )
        )

instead of


def _delete_plugin_entry(request,
                         entry_id,
                         entry_model_cls,
                         get_user_plugin_uids_func,
                         message,
                         html_anchor):
    """Abstract delete entry.

    :param django.http.HttpRequest request:
    :param int entry_id:
    :param fobi.models.AbstractPluginEntry entry_model_cls: Subclass of
        ``fobi.models.AbstractPluginEntry``.
    :param callable get_user_plugin_uids_func:
    :param str message:
    :return django.http.HttpResponse:
    """
    try:
        obj = entry_model_cls._default_manager \
                             .select_related('form_entry') \
                             .get(pk=entry_id,
                                  form_entry__user__pk=request.user.pk)
    except ObjectDoesNotExist as err:
        raise Http404(
            ugettext("{0} not found.").format(
                entry_model_cls._meta.verbose_name
            )
        )

and changing (starting at old line 628)

def delete_form_entry(request, form_entry_id, template_name=None):
    """Delete form entry.

    :param django.http.HttpRequest request:
    :param int form_entry_id:
    :param string template_name:
    :return django.http.HttpResponse:
    """
    try:
        obj = FormEntry._default_manager \
            .get(pk=form_entry_id, user__pk=request.user.pk)

to

def delete_form_entry(request, form_entry_id, template_name=None):
    """Delete form entry.

    :param django.http.HttpRequest request:
    :param int form_entry_id:
    :param string template_name:
    :return django.http.HttpResponse:
    """
    try:
        req_user_gruppe = request.user.groups.values_list("pk", flat=True)
        if request.user.is_staff==True:
            obj = FormEntry._default_manager \
                .get(pk=form_entry_id, work_user_group__pk__in=req_user_gruppe)
        else:
            obj = FormEntry._default_manager \
                .get(pk=form_entry_id, user__pk=request.user.pk)

one should also handle export etc. It is not completely worked out but working. So that a user can see all forms of all django-groups he belongs to If someone likes to see the full source code, tell me.

Update

It is also working with the current version 0.17.x I made a patch - if someone needs it.

joshuata commented 2 years ago

I would be willing to spearhead some work on this. I would like to make sure that whatever system we set up integrates well with any other object based permission systems and the Django permission api

I’ll look into what it would take in the next few days

joshuata commented 2 years ago

@barseghyanartur As I'm looking into this, would you prefer a pre-built system like Django-guardian or a custom authentication backend for fobi?

A custom backend would be less tested and reliable, but would allow us to customize the admin experience and would allow user who did not want to include all of guardian to still use the project. But guardian would have all the benefits of a battle tested system, we would just probably want to allow users to opt out of it

barseghyanartur commented 2 years ago

@joshuata:

I would prefer to keep things simple, but extendable. I'm currently working on the class based views and already implemented class based permissions. So, tailoring things to your needs would become much more simple (you won't have to maintain lots of changes).

Check this, this and this. I plan to finish it (and release it) in the upcoming two weeks.

barseghyanartur commented 2 years ago

Update. Class based views have been implemented (ATM do not cover form wizards). Class based views come with class based permissions. Implementing the form administrator roles is not trivial, but no longer a difficult task either.