diff --git a/MANIFEST.in b/MANIFEST.in index 3d387c3..21bdc73 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,2 +1,4 @@ include README.md -include requirements.txt \ No newline at end of file +include requirements.txt +recursive-include userextensions/templates * +recursive-include userextensions/templatetags * diff --git a/userextensions/__init__.py b/userextensions/__init__.py index 14f0bb2..bc96190 100644 --- a/userextensions/__init__.py +++ b/userextensions/__init__.py @@ -7,7 +7,7 @@ """ __title__ = 'django-userextensions' -__version__ = '0.0.3' +__version__ = '0.0.4' __author__ = 'David Slusser' __license__ = 'GPL-3.0' __copyright__ = 'Copyright 2019 David Slusser' diff --git a/userextensions/forms.py b/userextensions/forms.py new file mode 100644 index 0000000..abd4ffd --- /dev/null +++ b/userextensions/forms.py @@ -0,0 +1,17 @@ +from django import forms + +# import models +from userextensions.models import (UserPreference) + + +class UserPreferenceForm(forms.ModelForm): + """ Form class used to add/edit UserPreference objects """ + class Meta: + model = UserPreference + exclude = ['created_at', 'updated_at', 'user'] + widgets = { + 'recents_count': forms.NumberInput(attrs={'class': 'form-control'}), + 'page_refresh_time': forms.NumberInput(attrs={'class': 'form-control'}), + 'theme': forms.Select(attrs={'class': 'form-control'}), + 'start_page': forms.TextInput(attrs={'class': 'form-control'}), + } diff --git a/userextensions/templates/component/modals.htm b/userextensions/templates/component/modals.htm new file mode 100644 index 0000000..23c4970 --- /dev/null +++ b/userextensions/templates/component/modals.htm @@ -0,0 +1,429 @@ +{% block page_javascript %} + +{% endblock %} + + + + + + + + +
+ +
+ + + + + + + + + + + +
+ +
+ + + + + + + + +{##} +{##} +{#
#} +{# #} +{#
#} diff --git a/userextensions/templates/component/table_components.htm b/userextensions/templates/component/table_components.htm new file mode 100644 index 0000000..04a1e5c --- /dev/null +++ b/userextensions/templates/component/table_components.htm @@ -0,0 +1,29 @@ + + + + + + diff --git a/userextensions/templates/detail/detail_user.html b/userextensions/templates/detail/detail_user.html new file mode 100644 index 0000000..4f815c8 --- /dev/null +++ b/userextensions/templates/detail/detail_user.html @@ -0,0 +1,168 @@ +{% extends base_template|default:"userextensions_base.htm" %} +{% load staticfiles %} + +{% block content %} +
+

User Profile: {{ user.username }}


+

+ +
+
+
+
+ + +
+
+ Is Active: +
+
+ {% if user.is_active %} + + {% else %} + + {% endif %} +
+
+ + +
+
+ Is Staff: +
+
+ {% if user.is_staff %} + + {% else %} + + {% endif %} +
+
+ + +
+
+ Is Superuser: +
+
+ {% if user.is_superuser %} + + {% else %} + + {% endif %} +
+
+ + +
+
+ Date Joined: +
+
+ {{ user.date_joined }} +
+
+ + +
+
+ API Token: +
+
+ {{ token }}    + + + +
+
+
+
+
+ + +
 
+
+
+
+
+
+
+ Theme: +
+
+ {{ user.preference.theme }} +
+
+
+
+ Recents Count: +
+
+ {{ user.preference.recents_count }} +
+
+
+
+ Start Page: +
+
+ {{ user.preference.start_page }} +
+
+
+
+ Page Refresh: +
+
+ {{ user.preference.page_refresh_time }} +
+
+
+
Edit:
+
+ + + +
+
+
+
+ +
+ + +
 
+
+
+
+
+
+
+ Group Memberships: +
+
+
+ {% if groups %} + {% for group in groups %} +
{{ group }}
+ {% endfor %} + {% else %} +
no group memberships found
+ {% endif %} +
+
+
+
+
+
+ + + {% with form_data_user_preferences as form_data %} + {% include 'generic/generic_modal_form.htm' %} + {% endwith %} + +
 
+ {% include 'component/modals.htm' %} +{% endblock %} diff --git a/userextensions/templates/generic/generic_list.html b/userextensions/templates/generic/generic_list.html new file mode 100644 index 0000000..4f1d95a --- /dev/null +++ b/userextensions/templates/generic/generic_list.html @@ -0,0 +1,31 @@ +{% extends base_template|default:"userextensions_base.htm" %} +{% load staticfiles %} + +{% block local_head %} + {% include "component/table_components.htm" %} +{% endblock %} + +{% block content %} +
+

{{ title }}: {% if sub_title %}{{ sub_title }}{% endif %}

+ + {% if create_form %} +
{{ create_form.link_title }}
+ {% endif %} + + {% include table %} +
+ + {% include 'component/modals.htm' %} + + {# include generic modal form for the create form if passed from the view #} + {% with create_form as form_data %} + {% include 'generic/generic_modal_form.htm' %} + {% endwith %} + + {# include custom modal html/js template if passed in from the view #} + {% if modals %} + {% include modals %} + {% endif %} + +{% endblock %} diff --git a/userextensions/templates/snippets/user_theme.htm b/userextensions/templates/snippets/user_theme.htm new file mode 100644 index 0000000..7abdf00 --- /dev/null +++ b/userextensions/templates/snippets/user_theme.htm @@ -0,0 +1,13 @@ +{# +This snippet allows customizing the theme (css file) as defined per user in the UserPreference model theme field. +Include this snippet within the head tags of your base template: +{% include 'snippits/user_theme.htm' %} +#} + +{% get_theme request as user_theme %} +{% if user_theme %} + +{% else %} + +{% endif %} + diff --git a/userextensions/templates/table/table_favorites.htm b/userextensions/templates/table/table_favorites.htm new file mode 100644 index 0000000..5e33ab7 --- /dev/null +++ b/userextensions/templates/table/table_favorites.htm @@ -0,0 +1,28 @@ + + + + + + + + + + + {% for row in queryset %} + + + + + + + + + {% endfor %} + +
NameURLLast VisitedActions
{{ row.name }}{{ row.url }}{{ row.updated_at }} + + + +
diff --git a/userextensions/templates/table/table_recents.htm b/userextensions/templates/table/table_recents.htm new file mode 100644 index 0000000..8404c62 --- /dev/null +++ b/userextensions/templates/table/table_recents.htm @@ -0,0 +1,26 @@ + + + + + + + + + + {% for row in queryset %} + + + + + + + + {% endfor %} + +
URLLast VisitedActions
{{ row.url }}{{ row.updated_at }} + + + +
diff --git a/userextensions/templates/userextensions_base.htm b/userextensions/templates/userextensions_base.htm new file mode 100644 index 0000000..8023a13 --- /dev/null +++ b/userextensions/templates/userextensions_base.htm @@ -0,0 +1,23 @@ +{% load staticfiles %} +{% load userextension_tags %} + + + + + {% block mainheader %} + + + + + + + + + + + + + + {% endblock mainheader %} + + diff --git a/userextensions/urls.py b/userextensions/urls.py index 09f192d..f0bd33d 100644 --- a/userextensions/urls.py +++ b/userextensions/urls.py @@ -4,6 +4,14 @@ app_name = "userextensions" urlpatterns = [ + + # list views + path('list_recents/', views.ListRecents.as_view(), name='list_recents'), + path('list_favorites/', views.ListFavorites.as_view(), name='list_favorites'), + + # detail views + path('detail_user/', views.DetailUser.as_view(), name='detail_user'), + # create views path('add_favorite/', views.AddFavorite.as_view(), name='add_favorite'), diff --git a/userextensions/views.py b/userextensions/views.py index 94fa9dc..f53e8fa 100644 --- a/userextensions/views.py +++ b/userextensions/views.py @@ -2,16 +2,21 @@ shared views to facilitate user preference actions """ -from django.shortcuts import render, redirect +from django.shortcuts import render, redirect, reverse from django.contrib import messages +from django.conf import settings from django.utils import timezone -from django.views.generic import View, DeleteView +from django.views.generic import View, DeleteView, ListView from rest_framework.authtoken.models import Token +from djangohelpers.views import FilterByQueryParamsMixin from braces.views import LoginRequiredMixin # import models from userextensions.models import (UserRecent, UserFavorite, UserPreference) +# import forms +from userextensions.forms import UserPreferenceForm + class RefreshApiToken(LoginRequiredMixin, View): """ delete current user token and create a new one """ @@ -111,3 +116,68 @@ def post(self, request): extra_tags='alert-danger') return redirect(referrer) + +class ListRecents(LoginRequiredMixin, FilterByQueryParamsMixin, ListView): + """ display a list of urls the user has recently visited """ + base_template = settings.BASE_TEMPLATE + + def get(self, request, *args, **kwargs): + context = dict() + self.queryset = UserRecent.objects.filter(user=request.user).order_by('-updated_at') + template = "generic/generic_list.html" + context['queryset'] = self.filter_by_query_params() + context['title'] = "Recents" + context['sub_title'] = request.user.username + context['table'] = "table/table_recents.htm" + return render(request, template, context=context) + + +class ListFavorites(LoginRequiredMixin, FilterByQueryParamsMixin, ListView): + """ display a list of user defined favorites """ + base_template = settings.BASE_TEMPLATE + + def get(self, request, *args, **kwargs): + context = dict() + self.queryset = UserFavorite.objects.filter(user=request.user).order_by('-updated_at') + template = "generic/generic_list.html" + context['queryset'] = self.filter_by_query_params() + context['title'] = "Favorites" + context['sub_title'] = request.user.username + context['table'] = "table/table_favorites.htm" + return render(request, template, context=context) + + +class DetailUser(LoginRequiredMixin, View): + """ show user profile """ + base_template = settings.BASE_TEMPLATE + template = "detail/detail_user.html" + + def get(self, request): + context = dict() + # include user preference form + form_data_user_preferences = dict() + form_data_user_preferences['form'] = UserPreferenceForm(request.POST or None, instance=request.user.preference) + form_data_user_preferences['action'] = "Update" + form_data_user_preferences['action_url'] = reverse('userextensions:detail_user') + form_data_user_preferences['title'] = "Update Preferences: {} ".format(request.user) + form_data_user_preferences['modal_name'] = "update_user_preferences" + context['form_data_user_preferences'] = form_data_user_preferences + + context['user'] = request.user + context['token'] = str(Token.objects.get_or_create(user=request.user)[0]) + context['groups'] = sorted([i.name for i in request.user.groups.all()]) + context['base_template'] = self.base_template + return render(request, self.template, context=context) + + def post(self, request): + redirect_url = request.META.get('HTTP_REFERER') + form = UserPreferenceForm(request.POST or None, instance=request.user.preference) + if form.is_valid(): + form.save() + messages.add_message(request, messages.ERROR, "Preferences updated!", extra_tags='alert-info', ) + return redirect(redirect_url) + else: + for error in form.errors: + messages.add_message(request, messages.ERROR, "Input error: {}".format(error), + extra_tags='alert-danger', ) + return self.get(request)