def on_condominium_create(sender, instance, created, **kwargs): if created: weight = 0 for module in Modules.objects.all(): weight += 1 CondominiumModules.objects.create(condominium=instance, module=module, use=True, weight=weight) from condominium_management.models import ManagementPages ManagementPages.objects.create(condominium=instance, slug='tariffs', title=_('Tariffs'), content='') ManagementPages.objects.create(condominium=instance, slug='debtors', title=_('Debtors'), content='') ManagementPages.objects.create(condominium=instance, slug='ourmasters', title=_('Our masters'), content='') ManagementPages.objects.create(condominium=instance, slug='ourcontacts', title=_('Our contacts'), content='') directory = os.path.join(os.path.join(MEDIA_ROOT, 'documents'), str(instance.slug)) if not os.path.exists(directory): os.makedirs(directory) Forum = get_model('forum', 'Forum') ForumPermission = get_model('forum_permission', 'ForumPermission') GroupForumPermission = get_model('forum_permission', 'GroupForumPermission') Forum.objects.create(condominium=instance, type=0, name=_('Base users forum'), description=_('Basic forum for our Condominium.')) perms = ForumPermission.objects.all()[:19] group_user = Group.objects.get(name='User') group_manager = Group.objects.get(name='manager') forum = Forum.objects.get(condominium=instance) if not GroupForumPermission.objects.filter(forum=forum): for perm in enumerate(perms): GroupForumPermission.objects.create(permission=perm[1], forum=forum, group=group_manager) if perm[0] < 14: GroupForumPermission.objects.create(permission=perm[1], forum=forum, group=group_user)
class AbstractUploadImage(DatedModel): """Abstract model for images.""" file = models.ImageField( upload_to=image_directory_path, max_length=100, blank=True, validators=[ FileExtensionValidator(settings.IMAGE_TYPE_ALLOWED), validate_upload_image_file_size, ], ) forum = models.ForeignKey( get_model("forum", "Forum"), on_delete=models.CASCADE, verbose_name=_("Forum"), ) poster = models.ForeignKey( get_user_model(), on_delete=models.CASCADE, verbose_name=_("Poster"), ) class Meta: """Options for the `AbstractImage` model.""" abstract = True app_label = "ashley"
def update_trackers(self): # Fetch the list of ids of all descendant forums including the current one forum_ids = self.get_descendants(include_self=True).values_list('id', flat=True) # Determine the list of the associated topics, that is the list of topics # associated with the current forum plus the list of all topics associated # with the descendant forums. topic_klass = get_model('forum_conversation', 'Topic') topics = topic_klass.objects.filter(forum__id__in=forum_ids).order_by('-last_post_on') approved_topics = topics.filter(approved=True) self.topics_count = approved_topics.count() # Compute the forum level posts count (only approved posts are recorded) posts_count = sum(topic.posts_count for topic in topics) self.posts_count = posts_count # Force the forum 'last_post_on' date to the one associated with the topic with # the latest post. self.last_post_on = approved_topics[0].last_post_on if len(approved_topics) else None # Any save of a forum triggered from the update_tracker process will not result # in checking for a change of the forum's parent. self._simple_save() # Trigger the parent trackers update if necessary if self.parent: self.parent.update_trackers()
# -*- coding: utf-8 -*- from __future__ import unicode_literals from haystack import indexes from machina.core.db.models import get_model Post = get_model('forum_conversation', 'Post') class PostIndex(indexes.SearchIndex, indexes.Indexable): """ Defines the data stored in the Post indexes. """ text = indexes.CharField(document=True, use_template=True, template_name='forum_search/post_text.txt') poster = indexes.IntegerField(model_attr='poster_id', null=True) poster_name = indexes.CharField() forum = indexes.IntegerField(model_attr='topic__forum_id') forum_slug = indexes.CharField() forum_name = indexes.CharField() topic = indexes.IntegerField(model_attr='topic_id') topic_slug = indexes.CharField() topic_subject = indexes.CharField() created = indexes.DateTimeField(model_attr='created') updated = indexes.DateTimeField(model_attr='updated')
from django.http import HttpRequest from django.test import TestCase from machina.apps.forum_permission.shortcuts import assign_perm from machina.core.db.models import get_model from ashley.factories import ( ForumFactory, LTIContextFactory, PostFactory, TopicFactory, UserFactory, ) from ashley.machina_extensions.forum.views import OrderByColumnMixin Topic = get_model("forum_conversation", "Topic") class TestForumView(TestCase): """Displays the listing of forums overridden from django machina.""" def _get_url_list_forum_with_forums(self): """Creates four forums and a user to access the forum that has the permission to access it. It's a shortcut used in all the tests below. """ user = UserFactory() lti_context = LTIContextFactory(lti_consumer=user.lti_consumer) forum = ForumFactory(name="Z Letter") forum.lti_contexts.add(lti_context) # create 3 topics, and one topic with 10 posts topic = TopicFactory(forum=forum) for i in range(10): PostFactory(topic=topic)
from machina.apps.forum_conversation.utils import get_client_ip from machina.conf import settings as machina_settings from machina.core.db.models import get_model from machina.core.loading import get_class import re FLAG_THRESHOLD = 5 from nltk.corpus import stopwords stop_words = stopwords.words('english') + [""] from nltk.stem.porter import PorterStemmer porter = PorterStemmer() Attachment = get_model('forum_attachments', 'Attachment') Forum = get_model('forum', 'Forum') Post = get_model('forum_conversation', 'Post') Topic = get_model('forum_conversation', 'Topic') TopicPollOption = get_model('forum_polls', 'TopicPollOption') AttachmentFormset = get_class('forum_attachments.forms', 'AttachmentFormset') PostForm = get_class('forum_conversation.forms', 'PostForm') TopicForm = get_class('forum_conversation.forms', 'TopicForm') TopicPollOptionFormset = get_class('forum_polls.forms', 'TopicPollOptionFormset') TopicPollVoteForm = get_class('forum_polls.forms', 'TopicPollVoteForm') PostUpvoteForm = get_class('forum_conversation.forms', 'PostUpvoteForm') attachments_cache = get_class('forum_attachments.cache', 'cache')
""" Forum conversation model admin definitions ========================================== This module defines admin classes used to populate the Django administration dashboard. """ from django.contrib import admin from machina.core.db.models import get_model from machina.models.fields import MarkupTextField, MarkupTextFieldWidget Attachment = get_model('forum_attachments', 'Attachment') Post = get_model('forum_conversation', 'Post') Topic = get_model('forum_conversation', 'Topic') class AttachmentInline(admin.TabularInline): model = Attachment extra = 1 class PostAdmin(admin.ModelAdmin): """ The Post model admin. """ inlines = [ AttachmentInline, ] list_display = ('__str__', 'topic', 'poster', 'updated', 'approved') list_filter = (
import pytest from django.urls import reverse from faker import Faker from machina.core.db.models import get_model from machina.core.loading import get_class from machina.test.factories import ( ForumReadTrackFactory, PostFactory, TopicPollFactory, TopicPollOptionFactory, TopicPollVoteFactory, create_forum, create_topic ) from machina.test.testcases import BaseClientTestCase faker = Faker() ForumReadTrack = get_model('forum_tracking', 'ForumReadTrack') Post = get_model('forum_conversation', 'Post') Topic = get_model('forum_conversation', 'Topic') TopicPollVote = get_model('forum_polls', 'TopicPollVote') TopicReadTrack = get_model('forum_tracking', 'TopicReadTrack') PermissionHandler = get_class('forum_permission.handler', 'PermissionHandler') assign_perm = get_class('forum_permission.shortcuts', 'assign_perm') remove_perm = get_class('forum_permission.shortcuts', 'remove_perm') class TestTopicPollVoteView(BaseClientTestCase): @pytest.fixture(autouse=True) def setup(self): # Permission handler self.perm_handler = PermissionHandler()
# -*- coding: utf-8 -*- from __future__ import unicode_literals from machina.core.db.models import get_model from rest_framework import serializers Forum = get_model('forum', 'Forum') class ForumSerializer(serializers.ModelSerializer): description = serializers.SerializerMethodField() class Meta: model = Forum fields = [ 'id', 'name', 'slug', 'type', 'description', 'image', 'link', 'link_redirects', 'posts_count', 'topics_count', 'link_redirects_count', 'last_post_on', 'display_sub_forum_list', 'lft', 'rght', 'tree_id', 'level', 'parent', ] def get_description(self, obj): return obj.description.rendered
from django.contrib import messages from django.contrib.auth import get_user_model from django.contrib.auth.decorators import login_required from django.core.urlresolvers import reverse from django.utils.decorators import method_decorator from django.utils.translation import ugettext_lazy as _ from django.views.generic import DetailView from django.views.generic import ListView from django.views.generic import UpdateView # Local application / specific library imports from machina.conf import settings as machina_settings from machina.core.db.models import get_model from machina.core.loading import get_class Forum = get_model("forum", "Forum") ForumProfile = get_model("forum_member", "ForumProfile") Topic = get_model("forum_conversation", "Topic") ForumProfileForm = get_class("forum_member.forms", "ForumProfileForm") PermissionHandler = get_class("forum_permission.handler", "PermissionHandler") perm_handler = PermissionHandler() class UserTopicsView(ListView): """ Provides a list of all the topics in which the current user has posted messages. """
from django.contrib.auth import get_user_model from django.contrib.auth.mixins import LoginRequiredMixin from django.http import HttpResponseRedirect from django.shortcuts import get_object_or_404 from django.urls import reverse from django.utils.functional import cached_property from django.utils.translation import ugettext_lazy as _ from django.views.generic import DetailView, ListView, UpdateView from django.views.generic.detail import BaseDetailView, SingleObjectTemplateResponseMixin from machina.conf import settings as machina_settings from machina.core.db.models import get_model from machina.core.loading import get_class Forum = get_model('forum', 'Forum') ForumProfile = get_model('forum_member', 'ForumProfile') Post = get_model('forum_conversation', 'Post') Topic = get_model('forum_conversation', 'Topic') ForumProfileForm = get_class('forum_member.forms', 'ForumProfileForm') PermissionRequiredMixin = get_class('forum_permission.viewmixins', 'PermissionRequiredMixin') class UserPostsView(ListView): """ Provides a list of all the posts submitted by a given a user. """ context_object_name = 'posts' paginate_by = machina_settings.PROFILE_POSTS_NUMBER_PER_PAGE template_name = 'forum_member/user_posts_list.html'
# -*- coding: utf-8 -*- # Standard library imports from __future__ import unicode_literals # Third party imports from django.core.exceptions import ValidationError import pytest # Local application / specific library imports from machina.core.db.models import get_model from machina.test.factories import ForumPermissionFactory from machina.test.factories import UserFactory from machina.test.factories import UserForumPermissionFactory Forum = get_model('forum', 'Forum') ForumPermission = get_model('forum_permission', 'ForumPermission') UserForumPermission = get_model('forum_permission', 'UserForumPermission') @pytest.mark.django_db class TestForumPermission(object): def test_cannot_be_cleaned_without_local_or_global_flag(self): # Run & check with pytest.raises(ValidationError): perm = ForumPermissionFactory.build(is_local=False, is_global=False) perm.clean() @pytest.mark.django_db class TestUserForumPermission(object):
def test_are_registered_before_vanilla_models(self): klass = get_model('forum_conversation', 'Topic') assert 'tests._testsite.apps.forum_conversation.models' == klass.__module__
# Standard library imports from __future__ import unicode_literals # Third party imports from django import forms from django.core.exceptions import ValidationError from django.forms.models import BaseModelFormSet from django.forms.models import modelformset_factory from django.utils.translation import ugettext_lazy as _ # Local application / specific library imports from machina.core.db.models import get_model from machina.core.shortcuts import get_object_or_none TopicPoll = get_model("forum_polls", "TopicPoll") TopicPollOption = get_model("forum_polls", "TopicPollOption") class TopicPollOptionForm(forms.ModelForm): class Meta: model = TopicPollOption fields = ["text"] def __init__(self, *args, **kwargs): super(TopicPollOptionForm, self).__init__(*args, **kwargs) # Update the 'text' field self.fields["text"].label = "" self.fields["text"].widget.attrs["placeholder"] = _("Enter a poll option") self.fields["text"].required = False
from django.core.urlresolvers import reverse from faker import Factory as FakerFactory import pytest from machina.core.db.models import get_model from machina.core.loading import get_class from machina.test.factories import AttachmentFactory from machina.test.factories import create_forum from machina.test.factories import create_topic from machina.test.factories import ForumReadTrackFactory from machina.test.factories import PostFactory from machina.test.testcases import BaseClientTestCase faker = FakerFactory.create() Attachment = get_model('forum_attachments', 'Attachment') ForumReadTrack = get_model('forum_tracking', 'ForumReadTrack') Post = get_model('forum_conversation', 'Post') Topic = get_model('forum_conversation', 'Topic') TopicReadTrack = get_model('forum_tracking', 'TopicReadTrack') PermissionHandler = get_class('forum_permission.handler', 'PermissionHandler') assign_perm = get_class('forum_permission.shortcuts', 'assign_perm') remove_perm = get_class('forum_permission.shortcuts', 'remove_perm') class TestAttachmentView(BaseClientTestCase): @pytest.yield_fixture(autouse=True) def setup(self): # Permission handler self.perm_handler = PermissionHandler()
from django.http import HttpResponseRedirect from django.shortcuts import get_object_or_404 from django.utils.decorators import method_decorator from django.utils.functional import cached_property from django.utils.translation import ugettext_lazy as _ from django.views.generic import DetailView from django.views.generic import ListView from django.views.generic import UpdateView from django.views.generic.detail import BaseDetailView from django.views.generic.detail import SingleObjectTemplateResponseMixin from machina.conf import settings as machina_settings from machina.core.db.models import get_model from machina.core.loading import get_class Forum = get_model('forum', 'Forum') ForumProfile = get_model('forum_member', 'ForumProfile') Post = get_model('forum_conversation', 'Post') Topic = get_model('forum_conversation', 'Topic') ForumProfileForm = get_class('forum_member.forms', 'ForumProfileForm') PermissionRequiredMixin = get_class('forum_permission.viewmixins', 'PermissionRequiredMixin') class UserPostsView(ListView): """ Provides a list of all the posts submitted by a given a user. """ context_object_name = 'posts'
# -*- coding: utf-8 -*- from __future__ import unicode_literals import pytest from machina.core.db.models import get_model from machina.test.factories import create_category_forum from machina.test.factories import create_forum from machina.test.factories import create_link_forum from machina.test.factories import create_topic from machina.test.factories import ForumReadTrackFactory from machina.test.factories import PostFactory from machina.test.factories import UserFactory ForumReadTrack = get_model('forum_tracking', 'ForumReadTrack') @pytest.mark.django_db class TestForumReadTrackManager(object): @pytest.fixture(autouse=True) def setup(self): self.u1 = UserFactory.create() self.u2 = UserFactory.create() self.top_level_cat_1 = create_category_forum() self.top_level_cat_2 = create_category_forum() self.forum_1 = create_forum(parent=self.top_level_cat_1) self.forum_2 = create_forum(parent=self.top_level_cat_1) self.forum_2_child_1 = create_link_forum(parent=self.forum_2)
""" Forum attachments forms ======================= This module defines forms provided by the ``forum_attachments`` application. """ from django import forms from django.forms.models import BaseModelFormSet from django.forms.models import modelformset_factory from machina.conf import settings as machina_settings from machina.core.db.models import get_model Attachment = get_model('forum_attachments', 'Attachment') class AttachmentForm(forms.ModelForm): """ Allows to upload forum attachments. """ class Meta: model = Attachment fields = [ 'file', 'comment', ] class BaseAttachmentFormset(BaseModelFormSet): """ Base class allowing to define forum attachment formsets. """ def __init__(self, *args, **kwargs):
This module defines signal receivers. """ from django.contrib.auth import get_user_model from django.core.exceptions import ObjectDoesNotExist from django.db.models import F from django.db.models.signals import post_delete, pre_save from django.dispatch import receiver from machina.core.db.models import get_model User = get_user_model() Post = get_model('forum_conversation', 'Post') ForumProfile = get_model('forum_member', 'ForumProfile') @receiver(pre_save, sender=Post) def increase_posts_count(sender, instance, **kwargs): """ Increases the member's post count after a post save. This receiver handles the update of the profile related to the user who is the poster of the forum post being created or updated. """ if instance.poster is None: # An anonymous post is considered. No profile can be updated in # that case. return
from haystack.management.commands import rebuild_index from haystack.query import SearchQuerySet import pytest # Local application / specific library imports from machina.core.db.models import get_model from machina.core.loading import get_class from machina.test.factories import create_category_forum from machina.test.factories import create_forum from machina.test.factories import create_topic from machina.test.factories import PostFactory from machina.test.testcases import BaseClientTestCase faker = FakerFactory.create() Post = get_model('forum_conversation', 'Post') Topic = get_model('forum_conversation', 'Topic') PermissionHandler = get_class('forum_permission.handler', 'PermissionHandler') assign_perm = get_class('forum_permission.shortcuts', 'assign_perm') class TestFacetedSearchView(BaseClientTestCase): @pytest.yield_fixture(autouse=True) def setup(self): # Permission handler self.perm_handler = PermissionHandler() # Set up the following forum tree: # # top_level_cat
# -*- coding: utf-8 -*- # Standard library imports # Third party imports # Local application / specific library imports from machina.core.db.models import get_model from machina.core.loading import get_class Forum = get_model("forum", "Forum") ForumReadTrack = get_model("forum_tracking", "ForumReadTrack") TopicReadTrack = get_model("forum_tracking", "TopicReadTrack") PermissionHandler = get_class("forum_permission.handler", "PermissionHandler") class TrackingHandler(object): """ The TrackingHandler allows to filter list of forums and list of topics in order to get only the forums which contain unread topics or the unread topics. """ def __init__(self, request=None): self.request = request self.perm_handler = request.forum_permission_handler if request else PermissionHandler() def get_unread_forums(self, forums, user): """ Returns a list of unread forums for the given user from a given set of forums. """
Forum feeds =========== This module defines the feed abstractions provided by the forum application. It allows to generate RSS feeds. """ from django.contrib.syndication.views import Feed from django.shortcuts import get_object_or_404 from django.urls import reverse_lazy from django.utils.translation import gettext_lazy as _ from machina.core.db.models import get_model Forum = get_model('forum', 'Forum') Topic = get_model('forum_conversation', 'Topic') class LastTopicsFeed(Feed): """ Provides feed items for the latest forum topics. """ # Standard RSS elements title = _('Latest topics') description = _('Latest topics updated on the forums') link = reverse_lazy('forum:index') # Item elements title_template = 'forum_feeds/topics_title.html' description_template = 'forum_feeds/topics_description.html'
import collections import datetime as dt from functools import reduce from django.contrib.auth import get_user_model from django.db import models from django.utils.timezone import now from mptt.utils import get_cached_trees from machina.conf import settings as machina_settings from machina.core.db.models import get_model from machina.core.loading import get_class Forum = get_model('forum', 'Forum') GroupForumPermission = get_model('forum_permission', 'GroupForumPermission') Post = get_model('forum_conversation', 'Post') TopicPollVote = get_model('forum_polls', 'TopicPollVote') UserForumPermission = get_model('forum_permission', 'UserForumPermission') ForumPermissionChecker = get_class('forum_permission.checker', 'ForumPermissionChecker') get_anonymous_user_forum_key = get_class( 'forum_permission.shortcuts', 'get_anonymous_user_forum_key') class PermissionHandler: """ Defines filter / access logic related to forums. The ``PermissionHandler`` class allows to filter lists of forums and to perform permission
# -*- coding: utf-8 -*- from __future__ import unicode_literals from django import forms from django.core.exceptions import ObjectDoesNotExist from django.db.models import F from django.utils.translation import ugettext_lazy as _ from machina.conf import settings as machina_settings from machina.core.db.models import get_model from machina.core.loading import get_class Post = get_model('forum_conversation', 'Post') Topic = get_model('forum_conversation', 'Topic') TopicPoll = get_model('forum_polls', 'TopicPoll') PermissionHandler = get_class('forum_permission.handler', 'PermissionHandler') get_anonymous_user_forum_key = get_class('forum_permission.shortcuts', 'get_anonymous_user_forum_key') class PostForm(forms.ModelForm): class Meta: model = Post fields = [ 'subject', 'content', 'username', 'update_reason',
from django.contrib.auth.decorators import login_required from django.core.urlresolvers import reverse from django.http import HttpResponseRedirect from django.shortcuts import get_object_or_404 from django.utils.decorators import method_decorator from django.utils.translation import ugettext_lazy as _ from django.views.generic import ListView from django.views.generic import View # Local application / specific library imports from machina.conf import settings as machina_settings from machina.core.db.models import get_model from machina.core.loading import get_class from machina.core.loading import get_classes Forum = get_model('forum', 'Forum') ForumReadTrack, TopicReadTrack = get_classes('forum_tracking.models', ['ForumReadTrack', 'TopicReadTrack']) Topic = get_model('forum_conversation', 'Topic') TrackingHandler = get_class('forum_tracking.handler', 'TrackingHandler') track_handler = TrackingHandler() PermissionRequiredMixin = get_class('forum_permission.viewmixins', 'PermissionRequiredMixin') class MarkForumsReadView(View): """ Marks a set of forums as read. """ success_message = _('Forums have been marked read.')
from django.test import TestCase from machina.apps.forum_permission.shortcuts import assign_perm from machina.core.db.models import get_model from ashley.factories import ForumFactory, LTIContextFactory, UserFactory Forum = get_model("forum", "Forum") class ForumButtonManageModeratorTestCase(TestCase): """Test the display button to manage moderator on forum view""" def test_forum_display_button_manage_moderator(self): """ Connects a user with standard forum permission and controls that CTA to manage moderator is not present, then add the permission can_manage_moderator and control that we now see the CTA as expected """ user = UserFactory() lti_context = LTIContextFactory(lti_consumer=user.lti_consumer) forum = ForumFactory(name="Initial forum name") forum.lti_contexts.add(lti_context) assign_perm("can_read_forum", user, forum) # Connects user and go on the forum page self.client.force_login(user) response = self.client.get(f"/forum/forum/{forum.name}-{forum.id}/") # Check the CTA to manage moderators is not present self.assertNotContains( response, ('<a href="/moderators/" title="Manage moderators" class="dropdown-item">'
""" Forum conversation model admin definitions ========================================== This module defines admin classes used to populate the Django administration dashboard. """ from django.contrib import admin from machina.core.db.models import get_model from machina.models.fields import MarkupTextField, MarkupTextFieldWidget Attachment = get_model('forum_attachments', 'Attachment') Post = get_model('forum_conversation', 'Post') Topic = get_model('forum_conversation', 'Topic') class AttachmentInline(admin.TabularInline): model = Attachment extra = 1 class PostAdmin(admin.ModelAdmin): """ The Post model admin. """ inlines = [AttachmentInline, ] list_display = ('__str__', 'topic', 'poster', 'updated', 'approved') list_filter = ('created', 'updated',) raw_id_fields = ('poster', 'topic',)
# -*- coding: utf-8 -*- # Standard library imports # Third party imports from django.contrib import admin # Local application / specific library imports from machina.core.db.models import get_model Attachment = get_model("forum_attachments", "Attachment") Post = get_model("forum_conversation", "Post") Topic = get_model("forum_conversation", "Topic") class AttachmentInline(admin.TabularInline): model = Attachment extra = 1 class PostInline(admin.TabularInline): model = Post extra = 1 class PostAdmin(admin.ModelAdmin): inlines = [AttachmentInline] list_display = ("__str__", "topic", "poster", "updated", "approved") list_filter = ("created", "updated") raw_id_fields = ("poster",) search_fields = ("content",) list_editable = ("approved",)
# -*- coding: utf-8 -*- from __future__ import unicode_literals from django import forms from django.contrib import admin from machina.core.db.models import get_model Forum = get_model('forum', 'Forum') Topic = get_model('forum_conversation', 'Topic') TopicPoll = get_model('forum_polls', 'TopicPoll') TopicPollOption = get_model('forum_polls', 'TopicPollOption') TopicPollVote = get_model('forum_polls', 'TopicPollVote') class TopicPollForm(forms.ModelForm): def __init__(self, *args, **kwargs): super(TopicPollForm, self).__init__(*args, **kwargs) self.fields['topic'].queryset = Topic.objects.filter( forum__condominium=self.current_condominium) # class TopicPollOptionInline(admin.TabularInline): model = TopicPollOption extra = 1 class TopicPollOptionAdmin(admin.ModelAdmin): list_display = (
# -*- coding: utf-8 -*- # Standard library imports # Third party imports from django.contrib import admin # Local application / specific library imports from machina.core.db.models import get_model Attachment = get_model('forum_attachments', 'Attachment') class AttachmentAdmin(admin.ModelAdmin): list_display = ('id', 'post', 'comment', 'file', ) list_display_links = ('id', 'post', 'comment', ) raw_id_fields = ('post', ) admin.site.register(Attachment, AttachmentAdmin)
from django.core.urlresolvers import reverse from django.http import HttpResponseRedirect from django.shortcuts import get_object_or_404 from django.utils.translation import ugettext_lazy as _ from django.views.generic import DeleteView from django.views.generic import FormView from django.views.generic import ListView from django.views.generic.detail import SingleObjectMixin from machina.apps.forum_conversation.signals import topic_viewed from machina.apps.forum_conversation.utils import get_client_ip from machina.conf import settings as machina_settings from machina.core.db.models import get_model from machina.core.loading import get_class Attachment = get_model('forum_attachments', 'Attachment') Forum = get_model('forum', 'Forum') Post = get_model('forum_conversation', 'Post') Topic = get_model('forum_conversation', 'Topic') TopicPollOption = get_model('forum_polls', 'TopicPollOption') AttachmentFormset = get_class('forum_attachments.forms', 'AttachmentFormset') PostForm = get_class('forum_conversation.forms', 'PostForm') TopicForm = get_class('forum_conversation.forms', 'TopicForm') TopicPollOptionFormset = get_class('forum_polls.forms', 'TopicPollOptionFormset') TopicPollVoteForm = get_class('forum_polls.forms', 'TopicPollVoteForm') attachments_cache = get_class('forum_attachments.cache', 'cache') PermissionRequiredMixin = get_class('forum_permission.viewmixins', 'PermissionRequiredMixin')
This module defines forms provided by the ``forum_polls`` application. """ from django import forms from django.core.exceptions import ValidationError from django.forms.models import BaseModelFormSet, modelformset_factory from django.utils.translation import ugettext_lazy as _ from machina.conf import settings as machina_settings from machina.core.db.models import get_model from machina.core.shortcuts import get_object_or_none TopicPoll = get_model('forum_polls', 'TopicPoll') TopicPollOption = get_model('forum_polls', 'TopicPollOption') class TopicPollOptionForm(forms.ModelForm): class Meta: model = TopicPollOption fields = ['text', ] def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # Update the 'text' field self.fields['text'].label = '' self.fields['text'].widget.attrs['placeholder'] = _('Enter a poll option') self.fields['text'].required = False
""" Forum permission signal receivers ================================= This module defines signal receivers. """ from django.db.models.signals import post_migrate from django.dispatch import receiver from machina.core.db.models import get_model from machina.core.loading import get_class ForumPermission = get_model('forum_permission', 'ForumPermission') PermissionConfig = get_class('forum_permission.defaults', 'PermissionConfig') def create_permissions(): """ Creates all the permissions from the permission configuration. """ for config in PermissionConfig.permissions: ForumPermission.objects.get_or_create(codename=config['codename']) @receiver(post_migrate) def create_global_permissions(sender, **kwargs): """ Creates all the permissions from the permission configuration during migrations. """ if sender.name.endswith('forum_permission'): create_permissions()
# -*- coding: utf-8 -*- # Standard library imports # Third party imports from django.contrib import admin # Local application / specific library imports from machina.core.db.models import get_model from machina.models.fields import MarkupTextField from machina.models.fields import MarkupTextFieldWidget ForumProfile = get_model('forum_member', 'ForumProfile') class ForumProfileAdmin(admin.ModelAdmin): list_display = ('id', 'user', 'posts_count', ) list_filter = ('posts_count', ) list_display_links = ('id', 'user', ) raw_id_fields = ('user', ) search_fields = ('user__username',) formfield_overrides = { MarkupTextField: {'widget': MarkupTextFieldWidget}, } admin.site.register(ForumProfile, ForumProfileAdmin)
from __future__ import unicode_literals # Third party imports import pytest # Local application / specific library imports from machina.core.db.models import get_model from machina.test.factories import create_category_forum from machina.test.factories import create_forum from machina.test.factories import create_link_forum from machina.test.factories import create_topic from machina.test.factories import ForumReadTrackFactory from machina.test.factories import PostFactory from machina.test.factories import UserFactory ForumReadTrack = get_model('forum_tracking', 'ForumReadTrack') @pytest.mark.django_db class TestForumReadTrackManager(object): @pytest.fixture(autouse=True) def setup(self): self.u1 = UserFactory.create() self.u2 = UserFactory.create() self.top_level_cat_1 = create_category_forum() self.top_level_cat_2 = create_category_forum() self.forum_1 = create_forum(parent=self.top_level_cat_1) self.forum_2 = create_forum(parent=self.top_level_cat_1) self.forum_2_child_1 = create_link_forum(parent=self.forum_2)
# -*- coding: utf-8 -*- # Standard library imports from __future__ import unicode_literals # Third party imports import factory from faker import Factory as FakerFactory # Local application / specific library imports from machina.core.compat import slugify from machina.core.db.models import get_model faker = FakerFactory.create() Forum = get_model("forum", "Forum") class ForumFactory(factory.DjangoModelFactory): name = faker.text(max_nb_chars=150) slug = factory.LazyAttribute(lambda t: slugify(t.name)) # Link forum specific link = faker.uri() class Meta: model = Forum def build_forum(**attrs): """Create a new forum but do not save it."""
# -*- coding: utf-8 -*- # Standard library imports import mimetypes import os # Third party imports from django.http import HttpResponse from django.views.generic import DetailView # Local application / specific library imports from machina.core.db.models import get_model from machina.core.loading import get_class Attachment = get_model("forum_attachments", "Attachment") PermissionRequiredMixin = get_class("forum_permission.viewmixins", "PermissionRequiredMixin") class AttachmentView(PermissionRequiredMixin, DetailView): model = Attachment def render_to_response(self, context, **response_kwargs): filename = os.path.basename(self.object.file.name) # Try to guess the content type of the given file content_type, _ = mimetypes.guess_type(self.object.file.name) if not content_type: content_type = "text/plain" response = HttpResponse(self.object.file, content_type=content_type)
import pytest from django.core.exceptions import ValidationError from machina.core.db.models import get_model from machina.test.factories import ForumPermissionFactory from machina.test.factories import UserFactory from machina.test.factories import UserForumPermissionFactory Forum = get_model('forum', 'Forum') ForumPermission = get_model('forum_permission', 'ForumPermission') UserForumPermission = get_model('forum_permission', 'UserForumPermission') @pytest.mark.django_db class TestForumPermission(object): def test_cannot_be_cleaned_without_local_or_global_flag(self): # Run & check with pytest.raises(ValidationError): perm = ForumPermissionFactory.build(is_local=False, is_global=False) perm.clean() @pytest.mark.django_db class TestUserForumPermission(object): def test_cannot_target_an_anonymous_user_and_a_registered_user(self): # Setup user = UserFactory.create() # Run & check with pytest.raises(ValidationError): perm = ForumPermissionFactory.create(is_local=True, is_global=True)
# -*- coding: utf-8 -*- from __future__ import unicode_literals from django.db.models import F from django.db.models import Q from machina.core.db.models import get_model from machina.core.loading import get_class Forum = get_model('forum', 'Forum') ForumReadTrack = get_model('forum_tracking', 'ForumReadTrack') TopicReadTrack = get_model('forum_tracking', 'TopicReadTrack') PermissionHandler = get_class('forum_permission.handler', 'PermissionHandler') class TrackingHandler(object): """ The TrackingHandler allows to filter list of forums and list of topics in order to get only the forums which contain unread topics or the unread topics. """ def __init__(self, request=None): self.request = request self.perm_handler = request.forum_permission_handler if request \ else PermissionHandler() def get_unread_forums(self, forums, user): """ Returns a list of unread forums for the given user from a given
# Standard library imports from datetime import timedelta # Third party imports from django.contrib.auth import get_user_model from django.db.models import Q from django.shortcuts import _get_queryset from django.utils.timezone import now # Local application / specific library imports from machina.conf import settings as machina_settings from machina.core.db.models import get_model from machina.core.loading import get_class Forum = get_model("forum", "Forum") GroupForumPermission = get_model("forum_permission", "GroupForumPermission") Post = get_model("forum_conversation", "Post") UserForumPermission = get_model("forum_permission", "UserForumPermission") ForumPermissionChecker = get_class("forum_permission.checker", "ForumPermissionChecker") class PermissionHandler(object): """ The PermissionHandler allows to filter lists of forums and to perform permission verifications on forums. It uses the ForumPermissionChecker class to perform these verifications. """ def __init__(self):
from django.contrib.sites.models import Site from django.urls import reverse from machina.apps.forum.admin import PickUserForm from machina.apps.forum_permission.models import ForumPermission from machina.apps.forum_permission.models import GroupForumPermission from machina.apps.forum_permission.models import UserForumPermission from machina.core.db.models import get_model from machina.test.factories import GroupFactory from machina.test.factories import GroupForumPermissionFactory from machina.test.factories import UserFactory from machina.test.factories import UserForumPermissionFactory from machina.test.mixins import AdminBaseViewTestMixin from machina.test.testcases import AdminClientTestCase Forum = get_model('forum', 'Forum') class TestForumAdmin(AdminClientTestCase, AdminBaseViewTestMixin): model = Forum @pytest.fixture(autouse=True) def setup(self): # Set up a top-level category top_level_cat = Forum.objects.create(name='top_level_cat', type=Forum.FORUM_CAT) self.top_level_cat = top_level_cat # Set up some sub forums self.sub_forum_1 = Forum.objects.create(name='top_level_forum_1', type=Forum.FORUM_POST,
# Standard library imports from __future__ import unicode_literals # Third party imports from django import forms from django.core.exceptions import ObjectDoesNotExist from django.db.models import F from django.utils.translation import ugettext_lazy as _ # Local application / specific library imports from machina.conf import settings as machina_settings from machina.core.db.models import get_model from machina.core.loading import get_class Post = get_model('forum_conversation', 'Post') Topic = get_model('forum_conversation', 'Topic') TopicPoll = get_model('forum_polls', 'TopicPoll') PermissionHandler = get_class('forum_permission.handler', 'PermissionHandler') get_anonymous_user_forum_key = get_class('forum_permission.shortcuts', 'get_anonymous_user_forum_key') class PostForm(forms.ModelForm): class Meta: model = Post fields = ['subject', 'content', 'username', 'update_reason', ] def __init__(self, *args, **kwargs): self.user = kwargs.pop('user', None)
from django.db.models.signals import post_migrate from django.dispatch import receiver from machina.core.db.models import get_model from machina.core.loading import get_class ForumPermission = get_model('forum_permission', 'ForumPermission') PermissionConfig = get_class('forum_permission.defaults', 'PermissionConfig') def create_permissions(): for config in PermissionConfig.permissions: try: gp = ForumPermission.objects.get( codename=config['fields']['codename']) except ForumPermission.DoesNotExist: gp = ForumPermission(**config['fields']) gp.save() @receiver(post_migrate) def create_global_permissions(sender, **kwargs): if sender.name.endswith('forum_permission'): create_permissions()
# Standard library imports # Third party imports from django.contrib import messages from django.core.urlresolvers import reverse from django.forms.forms import NON_FIELD_ERRORS from django.http import HttpResponseRedirect from django.shortcuts import redirect from django.utils.translation import ugettext_lazy as _ from django.views.generic import UpdateView from django.views.generic.edit import ModelFormMixin # Local application / specific library imports from machina.core.db.models import get_model from machina.core.loading import get_class TopicPoll = get_model('forum_polls', 'TopicPoll') TopicPollVote = get_model('forum_polls', 'TopicPollVote') TopicPollVoteForm = get_class('forum_polls.forms', 'TopicPollVoteForm') PermissionRequiredMixin = get_class('forum_permission.viewmixins', 'PermissionRequiredMixin') class TopicPollVoteView(PermissionRequiredMixin, UpdateView): model = TopicPoll form_class = TopicPollVoteForm http_method_names = ['post', ] def get_form_kwargs(self): kwargs = super(ModelFormMixin, self).get_form_kwargs() kwargs['poll'] = self.object
# Standard library imports from __future__ import unicode_literals # Third party imports import pytest # Local application / specific library imports from machina.core.db.models import get_model from machina.test.factories import create_category_forum from machina.test.factories import create_forum from machina.test.factories import create_link_forum from machina.test.factories import create_topic from machina.test.factories import PostFactory from machina.test.factories import UserFactory Post = get_model('forum_conversation', 'Post') Topic = get_model('forum_conversation', 'Topic') @pytest.mark.django_db class TestApprovedManager(object): @pytest.fixture(autouse=True) def setup(self): self.u1 = UserFactory.create() # Set up a top-level category self.top_level_cat = create_category_forum() # Set up some forums self.forum_1 = create_forum(parent=self.top_level_cat) self.forum_2 = create_forum(parent=self.top_level_cat)
from machina.apps.forum_permission.viewmixins import ( PermissionRequiredMixin as BasePermissionRequiredMixin, ) from machina.core.db.models import get_model from machina.core.loading import get_class from ashley.permissions import ManageModeratorPermission from . import SESSION_LTI_CONTEXT_ID from .defaults import ( DEFAULT_FORUM_BASE_PERMISSIONS, DEFAULT_FORUM_BASE_READ_PERMISSIONS, DEFAULT_FORUM_BASE_WRITE_PERMISSIONS, DEFAULT_FORUM_ROLES_PERMISSIONS, ) GroupForumPermission = get_model("forum_permission", "GroupForumPermission") Forum = get_model("forum", "Forum") # pylint: disable=C0103 LTIContext = get_model("ashley", "LTIContext") # pylint: disable=C0103 PermissionRequiredMixin: BasePermissionRequiredMixin = get_class( "forum_permission.viewmixins", "PermissionRequiredMixin") User = get_user_model() logger = logging.getLogger(__name__) class ForumLTIView(BaseLTIAuthView): """Forum view called by an LTI launch request.""" def _do_on_login(self, lti_request: LTI) -> HttpResponse: """Process the request when the user is logged in via LTI""" # Get or create the LTIContext model associated with the current LTI launch request
from __future__ import unicode_literals from django.contrib import messages from django.core.urlresolvers import reverse from django.forms.forms import NON_FIELD_ERRORS from django.http import HttpResponseRedirect from django.shortcuts import redirect from django.utils.translation import ugettext_lazy as _ from django.views.generic import UpdateView from django.views.generic.edit import ModelFormMixin from machina.core.db.models import get_model from machina.core.loading import get_class TopicPoll = get_model('forum_polls', 'TopicPoll') TopicPollVote = get_model('forum_polls', 'TopicPollVote') TopicPollVoteForm = get_class('forum_polls.forms', 'TopicPollVoteForm') PermissionRequiredMixin = get_class('forum_permission.viewmixins', 'PermissionRequiredMixin') class TopicPollVoteView(PermissionRequiredMixin, UpdateView): """ Allows to vote in polls. """ model = TopicPoll form_class = TopicPollVoteForm http_method_names = [
# -*- coding: utf-8 -*- # Standard library imports from __future__ import unicode_literals # Third party imports from django.contrib.auth import get_user_model from django.contrib.auth.models import AnonymousUser from django.contrib.auth.models import Group # Local application / specific library imports from machina.core.db.models import get_model ForumPermission = get_model('forum_permission', 'ForumPermission') GroupForumPermission = get_model('forum_permission', 'GroupForumPermission') UserForumPermission = get_model('forum_permission', 'UserForumPermission') class NotUserNorGroup(Exception): pass def assign_perm(perm, user_or_group, forum=None, has_perm=True): """ Assign a permission to a user (anonymous or not) or a group. """ user, group = get_identity(user_or_group) perm = ForumPermission.objects.get(codename=perm) if user: return UserForumPermission.objects.create( forum=forum,
import datetime import json from io import BytesIO from django.contrib.auth import get_user_model from django.core.files.base import ContentFile from django.core.files.uploadedfile import SimpleUploadedFile from django.test import TestCase from django.test.utils import override_settings from machina.core.db.models import get_model from PIL import Image from ashley.factories import ForumFactory, UploadImageFactory, UserFactory User = get_user_model() UploadImage = get_model("ashley", "UploadImage") class ImageUploadApiTest(TestCase): """Test the API to upload image.""" def test_access_anonymous_api_upload_images_list(self): """Anonymous users should not be allowed to retrieve list of images""" response = self.client.get("/api/v1.0/images/") self.assertEqual(response.status_code, 403) content = json.loads(response.content) self.assertEqual( content, {"detail": "Authentication credentials were not provided."} ) def test_access_anonymous_api_upload_images_item(self):
import pytest from django.conf import settings from django.core.files.uploadedfile import SimpleUploadedFile from django.urls import reverse from machina.core.db.models import get_model from machina.core.loading import get_class from machina.test.factories import GroupFactory from machina.test.factories import PostFactory from machina.test.factories import UserFactory from machina.test.factories import create_category_forum from machina.test.factories import create_forum from machina.test.factories import create_topic from machina.test.testcases import BaseClientTestCase ForumProfile = get_model('forum_member', 'ForumProfile') PermissionHandler = get_class('forum_permission.handler', 'PermissionHandler') assign_perm = get_class('forum_permission.shortcuts', 'assign_perm') remove_perm = get_class('forum_permission.shortcuts', 'remove_perm') class TestUserPostsView(BaseClientTestCase): @pytest.fixture(autouse=True) def setup(self): # Add some users self.u1 = UserFactory.create() self.g1 = GroupFactory.create() self.u1.groups.add(self.g1) self.user.groups.add(self.g1)
from django.conf import settings from django.contrib.auth.models import Group from django.test import TestCase from lti_toolbox.factories import LTIConsumerFactory, LTIPassportFactory from machina.apps.forum_permission.viewmixins import ( PermissionRequiredMixin as BasePermissionRequiredMixin, ) from machina.core.db.models import get_model from machina.core.loading import get_class from ashley import SESSION_LTI_CONTEXT_ID from ashley.factories import UserFactory from tests.ashley.lti_utils import CONTENT_TYPE, sign_parameters Forum = get_model("forum", "Forum") LTIContext = get_model("ashley", "LTIContext") PermissionRequiredMixin: BasePermissionRequiredMixin = get_class( "forum_permission.viewmixins", "PermissionRequiredMixin") class ForumLTIViewTestCase(TestCase): """Test the ForumLTIView class""" def test_post_with_valid_lti_launch_request(self): """A user should be able to authenticate via a LTI launch request signed by a trusted consumer and passport.""" consumer = LTIConsumerFactory(slug="consumer") passport = LTIPassportFactory(title="consumer1_passport1", consumer=consumer)
from machina.core.db.models import get_model from machina.core.loading import get_class from machina.test.factories import create_category_forum from machina.test.factories import create_forum from machina.test.factories import create_link_forum from machina.test.factories import create_topic from machina.test.factories import GroupFactory from machina.test.factories import ForumReadTrackFactory from machina.test.factories import PostFactory from machina.test.factories import TopicReadTrackFactory from machina.test.factories import UserFactory faker = FakerFactory.create() Forum = get_model('forum', 'Forum') ForumReadTrack = get_model('forum_tracking', 'ForumReadTrack') TopicReadTrack = get_model('forum_tracking', 'TopicReadTrack') assign_perm = get_class('forum_permission.shortcuts', 'assign_perm') PermissionHandler = get_class('forum_permission.handler', 'PermissionHandler') TrackingHandler = get_class('forum_tracking.handler', 'TrackingHandler') @pytest.mark.django_db class TestTrackingHandler(object): @pytest.fixture(autouse=True) def setup(self): self.u1 = UserFactory.create() self.u2 = UserFactory.create() self.g1 = GroupFactory.create()
# Standard library imports from __future__ import unicode_literals # Third party imports from django import forms from django.core.exceptions import ValidationError from django.forms.models import BaseModelFormSet from django.forms.models import modelformset_factory from django.utils.translation import ugettext_lazy as _ # Local application / specific library imports from machina.conf import settings as machina_settings from machina.core.db.models import get_model from machina.core.shortcuts import get_object_or_none TopicPoll = get_model('forum_polls', 'TopicPoll') TopicPollOption = get_model('forum_polls', 'TopicPollOption') class TopicPollOptionForm(forms.ModelForm): class Meta: model = TopicPollOption fields = [ 'text', ] def __init__(self, *args, **kwargs): super(TopicPollOptionForm, self).__init__(*args, **kwargs) # Update the 'text' field self.fields['text'].label = ''
""" Forum permission shortcuts ========================== This module defines shortcut functions allowing to easily perform permission checks and to assign or remove granted permissions. """ from django.contrib.auth import get_user_model from django.contrib.auth.models import AnonymousUser, Group from machina.core.db.models import get_model ForumPermission = get_model('forum_permission', 'ForumPermission') GroupForumPermission = get_model('forum_permission', 'GroupForumPermission') UserForumPermission = get_model('forum_permission', 'UserForumPermission') class NotUserNorGroup(Exception): pass def assign_perm(perm, user_or_group, forum=None, has_perm=True): """ Assigns a permission to a user (anonymous or not) or a group. """ user, group = get_identity(user_or_group) perm = ForumPermission.objects.get(codename=perm) if user: return UserForumPermission.objects.create( forum=forum,
from __future__ import unicode_literals import datetime as dt from functools import reduce from django.contrib.auth import get_user_model from django.db.models import Q from django.shortcuts import _get_queryset from django.utils.timezone import now from mptt.utils import get_cached_trees from machina.conf import settings as machina_settings from machina.core.db.models import get_model from machina.core.loading import get_class Forum = get_model('forum', 'Forum') GroupForumPermission = get_model('forum_permission', 'GroupForumPermission') Post = get_model('forum_conversation', 'Post') TopicPollVote = get_model('forum_polls', 'TopicPollVote') UserForumPermission = get_model('forum_permission', 'UserForumPermission') ForumPermissionChecker = get_class('forum_permission.checker', 'ForumPermissionChecker') get_anonymous_user_forum_key = get_class('forum_permission.shortcuts', 'get_anonymous_user_forum_key') class PermissionHandler(object): """ The PermissionHandler allows to filter lists of forums and to perform