diff --git a/adhocracy-plus/config/urls.py b/adhocracy-plus/config/urls.py index b4f37a397..9fa9d9118 100644 --- a/adhocracy-plus/config/urls.py +++ b/adhocracy-plus/config/urls.py @@ -33,12 +33,14 @@ from apps.polls.api import PollViewSet from apps.polls.api import VoteViewSet from apps.polls.routers import QuestionDefaultRouter +from apps.projects.api import ProjectViewSet from apps.users.decorators import user_is_project_admin router = routers.DefaultRouter() router.register(r'follows', FollowViewSet, basename='follows') router.register(r'reports', ReportViewSet, basename='reports') router.register(r'polls', PollViewSet, basename='polls') +router.register(r'projects', ProjectViewSet, basename='projects') module_router = a4routers.ModuleDefaultRouter() # FIXME: rename to 'chapters' diff --git a/apps/projects/api.py b/apps/projects/api.py new file mode 100644 index 000000000..cea547b01 --- /dev/null +++ b/apps/projects/api.py @@ -0,0 +1,9 @@ +from rest_framework import viewsets + +from adhocracy4.projects.models import Project +from apps.projects.serializers import ProjectSerializer + + +class ProjectViewSet(viewsets.ReadOnlyModelViewSet): + queryset = Project.objects.all() + serializer_class = ProjectSerializer diff --git a/apps/projects/serializers.py b/apps/projects/serializers.py new file mode 100644 index 000000000..411571b8c --- /dev/null +++ b/apps/projects/serializers.py @@ -0,0 +1,44 @@ +from easy_thumbnails.files import get_thumbnailer +from rest_framework import serializers + +from adhocracy4.projects.models import Project + + +class ProjectSerializer(serializers.ModelSerializer): + title = serializers.SerializerMethodField() + url = serializers.SerializerMethodField() + organisation = serializers.SerializerMethodField() + tile_image = serializers.SerializerMethodField() + tile_image_copyright = serializers.SerializerMethodField() + + class Meta: + model = Project + fields = ['title', 'url', 'organisation', 'tile_image', + 'tile_image_copyright'] + + def get_title(self, instance): + return instance.name + + def get_url(self, instance): + return instance.get_absolute_url() + + def get_organisation(self, instance): + return instance.organisation.name + + def get_tile_image(self, instance): + image_url = '' + if instance.tile_image: + image = get_thumbnailer(instance.tile_image)['project_thumbnail'] + image_url = image.url + elif instance.image: + image = get_thumbnailer(instance.image)['project_thumbnail'] + image_url = image.url + return image_url + + def get_tile_image_copyright(self, instance): + if instance.tile_image: + return instance.tile_image_copyright + elif instance.image: + return instance.image_copyright + else: + return None diff --git a/apps/userdashboard/assets/js/a4_candy_userdashboard/ModerationProjects.jsx b/apps/userdashboard/assets/js/a4_candy_userdashboard/ModerationProjects.jsx new file mode 100644 index 000000000..bdb67e038 --- /dev/null +++ b/apps/userdashboard/assets/js/a4_candy_userdashboard/ModerationProjects.jsx @@ -0,0 +1,61 @@ +/* global fetch */ +import React from 'react' + +export default class ModerationProjects extends React.Component { + constructor (props) { + super(props) + + this.state = { + projectTitle: [], + organisation: [], + url: [], + projectImage: [], + imageCopyright: [] + } + } + + getProjectData (projectData) { + let i = 0 + for (i = 0; i < projectData.length; i++) { + var element = document.createElement('div') + element.setAttribute('class', 'col-sm-6 col-lg-4') + element.innerHTML = '
  • ' + '' + + '
    ' + '
    ' + '
    ' + '
    ' + '
    ' + + '' + projectData[i].organisation + '' + + '

    ' + projectData[i].title + '

    ' + + '
    ' + projectData[i].tile_image_copyright + '
    ' + '
    ' + '
  • ' + + $('#project_list').append(element) + this.setState({ + projectTitle: this.state.projectTitle.concat(projectData[i].title), + organisation: this.state.organisation.concat(projectData[i].organisation), + url: this.state.url.concat(projectData[i].url), + projectImage: this.state.projectImage.concat(projectData[i].tile_image), + imageCopyright: this.state.imageCopyright.concat(projectData[i].tile_image_copyright) + }) + } + } + + getItems () { + fetch(this.props.projectApiUrl) + .then((response) => { + return response.json() + }).then((data) => { + this.getProjectData(data) + }) + } + + componentDidMount () { + this.getItems() + } + + render () { + return ( +
    +

    Projects

    +
    +
    + ) + } +} diff --git a/apps/userdashboard/assets/js/a4_candy_userdashboard/react_moderation_projects.jsx b/apps/userdashboard/assets/js/a4_candy_userdashboard/react_moderation_projects.jsx new file mode 100644 index 000000000..f5db5fa5b --- /dev/null +++ b/apps/userdashboard/assets/js/a4_candy_userdashboard/react_moderation_projects.jsx @@ -0,0 +1,18 @@ +import ModerationProjects from './ModerationProjects' +import React from 'react' +import ReactDOM from 'react-dom' + +function init () { + $('[data-aplus-widget="moderation_projects"').each(function (i, element) { + const moderationProjects = element.getAttribute('data-moderation-projects') + const projectApiUrl = element.getAttribute('data-project-api-url') + ReactDOM.render( + , + element) + }) +} + +document.addEventListener('DOMContentLoaded', init, false) diff --git a/apps/userdashboard/templates/a4_candy_userdashboard/userdashboard_moderation.html b/apps/userdashboard/templates/a4_candy_userdashboard/userdashboard_moderation.html index 5680c84eb..598e7091f 100644 --- a/apps/userdashboard/templates/a4_candy_userdashboard/userdashboard_moderation.html +++ b/apps/userdashboard/templates/a4_candy_userdashboard/userdashboard_moderation.html @@ -1,3 +1,14 @@ {% extends "a4_candy_userdashboard/base_userdashboard.html" %} +{% load i18n static %} -{% block dashboard_content %}{% endblock %} +{% block extra_js %} + {{ block.super }} + +{% endblock %} + +{% block dashboard_content %} +
    +
    +{% endblock %} diff --git a/apps/userdashboard/views.py b/apps/userdashboard/views.py index c21fe7562..d14ca1e94 100644 --- a/apps/userdashboard/views.py +++ b/apps/userdashboard/views.py @@ -1,4 +1,5 @@ from django.contrib.auth.mixins import LoginRequiredMixin +from django.urls import reverse from django.views import generic from adhocracy4.actions.models import Action @@ -12,6 +13,12 @@ class UserDashboardBaseMixin(LoginRequiredMixin, generic.base.ContextMixin, generic.base.TemplateResponseMixin, generic.base.View): + """ + Adds followed projects and organisations as properties. + + To be used in the user dashboard views, as they all need this info. + """ + model = User def get(self, request): @@ -31,6 +38,7 @@ def projects(self): follow__enabled=True) +# user views class UserDashboardOverviewView(UserDashboardBaseMixin): template_name = 'a4_candy_userdashboard/userdashboard_overview.html' @@ -50,14 +58,6 @@ def projects_carousel(self): list(sorted_future_projects))[:9] -class UserDashboardModerationView(UserDashboardBaseMixin, - rules_mixins.PermissionRequiredMixin): - - template_name = 'a4_candy_userdashboard/userdashboard_moderation.html' - permission_required = 'a4_candy_userdashboard.view_moderation_dashboard' - menu_item = 'moderation' - - class UserDashboardActivitiesView(UserDashboardBaseMixin): template_name = 'a4_candy_userdashboard/userdashboard_activities.html' @@ -74,3 +74,22 @@ class UserDashboardFollowingView(UserDashboardBaseMixin): template_name = 'a4_candy_userdashboard/userdashboard_following.html' menu_item = 'overview' + + +# moderation views +class UserDashboardModerationView(UserDashboardBaseMixin, + rules_mixins.PermissionRequiredMixin): + + template_name = 'a4_candy_userdashboard/userdashboard_moderation.html' + permission_required = 'a4_candy_userdashboard.view_moderation_dashboard' + menu_item = 'moderation' + + def get_projects(self): + projects = list(self.request.user.project_moderator.all()) + return projects + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context['moderation_projects'] = self. get_projects() + context['project_api_url'] = reverse('projects-list') + return context diff --git a/webpack.common.js b/webpack.common.js index 8f065fa2c..9f7688729 100644 --- a/webpack.common.js +++ b/webpack.common.js @@ -72,6 +72,9 @@ module.exports = { ], select_dropdown_init: [ 'adhocracy4/adhocracy4/categories/assets/select_dropdown_init.js' + ], + moderation_projects: [ + './apps/userdashboard/assets/js/a4_candy_userdashboard/react_moderation_projects.jsx' ] }, output: {