def test_raise_importerror_if_app_raises_importerror(self): # Setup apps = list(settings.INSTALLED_APPS) apps[apps.index('machina.apps.forum')] = 'tests._testsite.importerror_app.forum' with override_settings(INSTALLED_APPS=apps): with pytest.raises(ImportError): get_class('forum.dummy', 'Dummy')
def update_user_trackers(sender, topic, user, request, response, **kwargs): """ Receiver to mark a topic being viewed as read. This can result in marking the related forum tracker as read. """ TrackingHandler = get_class('forum_tracking.handler', 'TrackingHandler') # noqa track_handler = TrackingHandler() track_handler.mark_topic_read(topic, user)
# -*- coding: utf-8 -*- # Standard library imports from __future__ import unicode_literals # Third party imports from django.dispatch import receiver # Local application / specific library imports from machina.core.loading import get_class topic_viewed = get_class('forum_conversation.signals', 'topic_viewed') @receiver(topic_viewed) def update_user_trackers(sender, topic, user, request, response, **kwargs): """ Receiver to mark a topic being viewed as read. This can result in marking the related forum tracker as read. """ TrackingHandler = get_class('forum_tracking.handler', 'TrackingHandler') # noqa track_handler = TrackingHandler() track_handler.mark_topic_read(topic, user)
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' user_pk_url_kwarg = 'pk' def get_context_data(self, **kwargs): """ Returns the context data to provide to the template. """ context = super().get_context_data(**kwargs)
# Local application / specific library imports from machina.apps.forum_permission.middleware import ForumPermissionMiddleware 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 ForumReadTrackFactory from machina.test.factories import GroupFactory from machina.test.factories import PostFactory from machina.test.factories import TopicReadTrackFactory from machina.test.factories import UserFactory Forum = get_model('forum', 'Forum') assign_perm = get_class('forum_permission.shortcuts', 'assign_perm') TrackingHandler = get_class('forum_tracking.handler', 'TrackingHandler') @pytest.mark.django_db class BaseTrackingTagsTestCase(object): @pytest.fixture(autouse=True) def setUp(self): self.loadstatement = '{% load forum_tracking_tags %}' self.request_factory = RequestFactory() # Tracking handler self.tracks_handler = TrackingHandler() self.g1 = GroupFactory.create()
# -*- coding: utf-8 -*- # Standard library imports from __future__ import unicode_literals # Third party imports from django.dispatch import receiver # Local application / specific library imports from machina.core.loading import get_class ForumPermission = get_class('forum_permission.models', 'ForumPermission') PermissionConfig = get_class('forum_permission.defaults', 'PermissionConfig') def create_permissions(): for config in PermissionConfig.permissions: try: gp = ForumPermission.objects.get(codename=config['codename']) except ForumPermission.DoesNotExist: gp = ForumPermission(**config) gp.save() try: from django.db.models.signals import post_migrate @receiver(post_migrate) def create_global_permissions(sender, **kwargs): if sender.name.endswith('forum_permission'): create_permissions()
""" 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()
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 verifications on forums. It uses the ``ForumPermissionChecker`` class to perform these verifications. """ def __init__(self):
def test_raises_if_the_class_name_is_incorrect(self): # Run & check with pytest.raises(ClassNotFoundError): get_class('forum.models', 'Foo')
def test_raises_if_the_module_label_is_incorrect(self): # Run & check with pytest.raises(AppNotFoundError): get_class('foo.bar', 'Forum')
def test_can_load_a_single_class(self): # Run & check LastTopicsFeed = get_class('forum_feeds.feeds', 'LastTopicsFeed') # noqa assert 'machina.apps.forum_feeds.feeds' == LastTopicsFeed.__module__
from django.template.base import Template from django.template.loader import render_to_string from django.test.client import RequestFactory from machina.apps.forum_permission.middleware import ForumPermissionMiddleware from machina.core.db.models import get_model from machina.core.loading import get_class from machina.test.factories import UserFactory from machina.test.factories import create_category_forum from machina.test.factories import create_forum Forum = get_model('forum', 'Forum') Post = get_model('forum_conversation', 'Post') Topic = get_model('forum_conversation', 'Topic') ForumVisibilityContentTree = get_class('forum.visibility', 'ForumVisibilityContentTree') PermissionHandler = get_class('forum_permission.handler', 'PermissionHandler') assign_perm = get_class('forum_permission.shortcuts', 'assign_perm') @pytest.mark.django_db class TestForumListTag(object): @pytest.fixture(autouse=True) def setup(self): self.loadstatement = '{% load forum_tags %}' self.request_factory = RequestFactory() self.user = UserFactory.create() # Set up a top-level category self.top_level_cat = create_category_forum()
# -*- coding: utf-8 -*- from __future__ import unicode_literals from django import template from machina.core.db.models import get_model from machina.core.loading import get_class TopicPollVote = get_model('forum_polls', 'TopicPollVote') get_anonymous_user_forum_key = get_class('forum_permission.shortcuts', 'get_anonymous_user_forum_key') register = template.Library() @register.filter def has_been_completed_by(poll, user): """ This will return a boolean indicating if the passed user has already voted in the given poll. Usage:: {% if poll|has_been_completed_by:user %}...{% endif %} """ user_votes = TopicPollVote.objects.filter(poll_option__poll=poll) if user.is_anonymous(): forum_key = get_anonymous_user_forum_key(user) user_votes = user_votes.filter(anonymous_key=forum_key) if forum_key \ else user_votes.none() else:
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import PermissionDenied from django.test import RequestFactory from django.views.generic import DetailView import pytest # Local application / specific library imports from machina.apps.forum_permission.middleware import ForumPermissionHandlerMiddleware from machina.core.db.models import get_model from machina.core.loading import get_class from machina.test.factories import create_forum from machina.test.factories import UserFactory Forum = get_model('forum', 'Forum') PermissionHandler = get_class('forum_permission.handler', 'PermissionHandler') assign_perm = get_class('forum_permission.shortcuts', 'assign_perm') PermissionRequiredMixin = get_class('forum_permission.viewmixins', 'PermissionRequiredMixin') @pytest.mark.django_db class TestPermissionRequiredMixin(object): @pytest.fixture(autouse=True) def setup(self): self.user = UserFactory.create() self.factory = RequestFactory() # Permission handler self.perm_handler = PermissionHandler()
# -*- coding: utf-8 -*- from __future__ import unicode_literals from django import template from machina.core.loading import get_class TrackingHandler = get_class('forum_tracking.handler', 'TrackingHandler') register = template.Library() @register.assignment_tag(takes_context=True) def get_unread_forums(context, forums, user): """ This will return a list of unread forums for the given user from a given set of forums. Usage:: {% get_unread_forums forums request.user as unread_forums %} """ request = context.get('request', None) return TrackingHandler(request=request).get_unread_forums(forums, user) @register.assignment_tag(takes_context=True) def get_unread_topics(context, topics, user): """ This will return a list of unread topics for the given user from a given set of forums.
def test_can_load_a_class_defined_in_a_local_module(self): with override_settings(INSTALLED_APPS=self.installed_apps): MyNewForumView = get_class('forum.views', 'MyNewForumView') # noqa assert 'tests._testsite.apps.forum.views' == MyNewForumView.__module__
def test_can_load_a_class_from_an_app_module_that_is_not_present_in_the_local_app_module(self): with override_settings(INSTALLED_APPS=self.installed_apps): ForumAdmin = get_class('forum.admin', 'ForumAdmin') # noqa assert 'machina.apps.forum.admin' == ForumAdmin.__module__
def test_raise_importerror_if_the_app_is_installed_but_the_module_does_not_exist( self): # Run & check with pytest.raises(AppNotFoundError): get_class('forum.xyz', 'Xyz')
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') Post = get_model('forum_conversation', 'Post') 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. """ template_name = 'forum_member/user_topics_list.html' context_object_name = 'topics' paginate_by = machina_settings.FORUM_TOPICS_NUMBER_PER_PAGE def get_queryset(self):
from django import template from machina.core.db.models import get_model from machina.core.loading import get_class TopicPollVote = get_model('forum_polls', 'TopicPollVote') get_anonymous_user_forum_key = get_class( 'forum_permission.shortcuts', 'get_anonymous_user_forum_key', ) register = template.Library() @register.filter def has_been_completed_by(poll, user): """ This will return a boolean indicating if the passed user has already voted in the given poll. Usage:: {% if poll|has_been_completed_by:user %}...{% endif %} """ user_votes = TopicPollVote.objects.filter( poll_option__poll=poll) if user.is_anonymous: forum_key = get_anonymous_user_forum_key(user) user_votes = user_votes.filter(anonymous_key=forum_key) if forum_key \ else user_votes.none() else:
def test_can_load_a_class_that_is_not_defined_in_the_local_module(self): with override_settings(INSTALLED_APPS=self.installed_apps): ForumView = get_class('forum.views', 'ForumView') # noqa assert 'machina.apps.forum.views' == ForumView.__module__
# 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) self.user_ip = kwargs.pop('user_ip', None) self.forum = kwargs.pop('forum', None) self.topic = kwargs.pop('topic', None)
def test_can_load_a_class_from_an_app_module_that_is_not_present_in_the_local_app_module( self): with override_settings(INSTALLED_APPS=self.installed_apps): ForumAdmin = get_class('forum.admin', 'ForumAdmin') # noqa assert 'machina.apps.forum.admin' == ForumAdmin.__module__
# -*- coding: utf-8 -*- from __future__ import unicode_literals from django.conf import settings from django.db import models from django.utils.encoding import python_2_unicode_compatible from django.utils.translation import ugettext_lazy as _ from machina.core.loading import get_class ForumReadTrackManager = get_class('forum_tracking.managers', 'ForumReadTrackManager') @python_2_unicode_compatible class AbstractForumReadTrack(models.Model): """ Represents a track which records which forums have been read by a given user. """ user = models.ForeignKey( settings.AUTH_USER_MODEL, related_name='forum_tracks', verbose_name=_('User')) forum = models.ForeignKey('forum.Forum', verbose_name=_('Forum'), related_name='tracks') mark_time = models.DateTimeField(auto_now=True) objects = ForumReadTrackManager() class Meta: abstract = True app_label = 'forum_tracking' unique_together = ['user', 'forum', ] verbose_name = _('Forum track')
from django import template from django.utils.safestring import mark_safe from machina.core.db.models import get_model from machina.core.loading import get_class Forum = get_model('forum', 'Forum') PermissionHandler = get_class('forum_permission.handler', 'PermissionHandler') TrackingHandler = get_class('forum_tracking.handler', 'TrackingHandler') register = template.Library() class RecurseTreeForumVisibilityContentNode(template.Node): def __init__(self, template_nodes, forums_contents_var): self.template_nodes = template_nodes self.forums_contents_var = forums_contents_var def _render_node(self, context, node): bits = [] context.push() for child in node.children: bits.append(self._render_node(context, child)) context['node'] = node context['children'] = mark_safe(''.join(bits)) rendered = self.template_nodes.render(context) context.pop() return rendered
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import PermissionDenied from django.test import RequestFactory from django.views.generic import DetailView import pytest # Local application / specific library imports from machina.apps.forum_permission.middleware import ForumPermissionMiddleware from machina.core.db.models import get_model from machina.core.loading import get_class from machina.test.factories import create_forum from machina.test.factories import UserFactory Forum = get_model('forum', 'Forum') PermissionHandler = get_class('forum_permission.handler', 'PermissionHandler') assign_perm = get_class('forum_permission.shortcuts', 'assign_perm') PermissionRequiredMixin = get_class('forum_permission.viewmixins', 'PermissionRequiredMixin') @pytest.mark.django_db class TestPermissionRequiredMixin(object): @pytest.fixture(autouse=True) def setup(self): self.user = UserFactory.create() self.factory = RequestFactory() # Permission handler self.perm_handler = PermissionHandler()
from mptt.models import MPTTModel from mptt.models import TreeForeignKey # Local application / specific library imports from machina.apps.forum import signals from machina.conf import settings as machina_settings from machina.core.compat import slugify from machina.core.db.models import get_model from machina.core.loading import get_class from machina.core.utils import refresh from machina.models import ActiveModel from machina.models import DatedModel from machina.models.fields import ExtendedImageField from machina.models.fields import MarkupTextField ForumManager = get_class('forum.managers', 'ForumManager') FORUM_TYPES = Choices( (0, 'forum_post', _('Default forum')), (1, 'forum_cat', _('Category forum')), (2, 'forum_link', _('Link forum')), ) @python_2_unicode_compatible class AbstractForum(MPTTModel, ActiveModel, DatedModel): """ The main forum model. The tree hierarchy of forums and categories is managed by the MPTTModel which is part of django-mptt.
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() # Set up a top-level forum self.top_level_forum = create_forum() # Set up a topic and some posts self.topic = create_topic(forum=self.top_level_forum, poster=self.user)
class ModerationApp(Application): name = 'forum_moderation' topic_lock_view = get_class('forum_moderation.views', 'TopicLockView') topic_unlock_view = get_class('forum_moderation.views', 'TopicUnlockView') topic_delete_view = get_class('forum_moderation.views', 'TopicDeleteView') topic_move_view = get_class('forum_moderation.views', 'TopicMoveView') topic_update_to_normal_topic_view = get_class( 'forum_moderation.views', 'TopicUpdateToNormalTopicView') topic_update_to_sticky_topic_view = get_class( 'forum_moderation.views', 'TopicUpdateToStickyTopicView') topic_update_to_announce_view = get_class('forum_moderation.views', 'TopicUpdateToAnnounceView') topic_update_to_tips_view = get_class('forum_moderation.views', 'TopicUpdateToTipsView') topic_update_to_studymaterials_view = get_class( 'forum_moderation.views', 'TopicUpdateToStudymaterialsView') topic_update_to_newsstories_view = get_class( 'forum_moderation.views', 'TopicUpdateToNewsstoriesView') moderation_queue_list_view = get_class('forum_moderation.views', 'ModerationQueueListView') moderation_queue_detail_view = get_class('forum_moderation.views', 'ModerationQueueDetailView') post_approve_view = get_class('forum_moderation.views', 'PostApproveView') post_disapprove_view = get_class('forum_moderation.views', 'PostDisapproveView') def get_urls(self): return [ url(_(r'^topic/(?P<slug>[\w-]+)-(?P<pk>\d+)/lock/$'), self.topic_lock_view.as_view(), name='topic_lock'), url(_(r'^topic/(?P<slug>[\w-]+)-(?P<pk>\d+)/unlock/$'), self.topic_unlock_view.as_view(), name='topic_unlock'), url(_(r'^topic/(?P<slug>[\w-]+)-(?P<pk>\d+)/delete/$'), self.topic_delete_view.as_view(), name='topic_delete'), url(_(r'^topic/(?P<slug>[\w-]+)-(?P<pk>\d+)/move/$'), self.topic_move_view.as_view(), name='topic_move'), url(_(r'^topic/(?P<slug>[\w-]+)-(?P<pk>\d+)/change/topic/$'), self.topic_update_to_normal_topic_view.as_view(), name='topic_update_to_post'), url(_(r'^topic/(?P<slug>[\w-]+)-(?P<pk>\d+)/change/sticky/$'), self.topic_update_to_sticky_topic_view.as_view(), name='topic_update_to_sticky'), url(_(r'^topic/(?P<slug>[\w-]+)-(?P<pk>\d+)/change/announce/$'), self.topic_update_to_announce_view.as_view(), name='topic_update_to_announce'), url(_(r'^topic/(?P<slug>[\w-]+)-(?P<pk>\d+)/change/tips/$'), self.topic_update_to_tips_view.as_view(), name='topic_update_to_tips'), url(_( r'^topic/(?P<slug>[\w-]+)-(?P<pk>\d+)/change/studymaterials/$' ), self.topic_update_to_studymaterials_view.as_view(), name='topic_update_to_studymaterials'), url(_(r'^topic/(?P<slug>[\w-]+)-(?P<pk>\d+)/change/newsstories/$'), self.topic_update_to_newsstories_view.as_view(), name='topic_update_to_newsstories'), url(_(r'^queue/$'), self.moderation_queue_list_view.as_view(), name='queue'), url(_(r'^queue/(?P<pk>\d+)/$'), self.moderation_queue_detail_view.as_view(), name='queued_post'), url(_(r'^queue/(?P<pk>\d+)/approve/$'), self.post_approve_view.as_view(), name='approve_queued_post'), url(_(r'^queue/(?P<pk>\d+)/disapprove/$'), self.post_disapprove_view.as_view(), name='disapprove_queued_post'), ]
def test_raise_importerror_if_the_app_is_installed_but_the_module_does_not_exist(self): # Run & check with pytest.raises(AppNotFoundError): get_class('forum.xyz', 'Xyz')
# Standard library imports from __future__ import unicode_literals # Third party imports from django.db.models import F from django.db.models import Q # 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): """
from django.shortcuts import get_object_or_404, redirect, render from django.urls import reverse from django.utils.translation import gettext_lazy as _ from mptt.exceptions import InvalidMove from machina.core.db.models import get_model from machina.core.loading import get_class from machina.models.fields import MarkupTextField, MarkupTextFieldWidget Forum = get_model('forum', 'Forum') ForumPermission = get_model('forum_permission', 'ForumPermission') GroupForumPermission = get_model('forum_permission', 'GroupForumPermission') UserForumPermission = get_model('forum_permission', 'UserForumPermission') PermissionsForm = get_class('forum.forms', 'PermissionsForm') PickForumForm = get_class('forum.forms', 'PickForumForm') PickGroupForm = get_class('forum.forms', 'PickGroupForm') PickUserForm = get_class('forum.forms', 'PickUserForm') PermissionConfig = get_class('forum_permission.defaults', 'PermissionConfig') class ForumAdmin(admin.ModelAdmin): """ The Forum model admin. """ formfield_overrides = { MarkupTextField: {'widget': MarkupTextFieldWidget}, } fieldsets = (
# -*- 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. """
from django.views.generic.detail import SingleObjectMixin # Local application / specific library imports 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') class TopicView(PermissionRequiredMixin, ListView): """ Displays a forum topic.
from django import template from machina.core.loading import get_class TrackingHandler = get_class('forum_tracking.handler', 'TrackingHandler') register = template.Library() @register.simple_tag(takes_context=True) def get_unread_topics(context, topics, user): """ This will return a list of unread topics for the given user from a given set of topics. Usage:: {% get_unread_topics topics request.user as unread_topics %} """ request = context.get('request', None) return TrackingHandler(request=request).get_unread_topics(topics, user)
from django.contrib import messages from django.forms.forms import NON_FIELD_ERRORS from django.http import HttpResponseRedirect from django.shortcuts import redirect from django.urls import reverse 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 = [ 'post', ]
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.') def get(self, request, pk=None): top_level_forum = None if pk is not None:
from django.views.generic import ListView from django.views.generic.detail import BaseDetailView from django.views.generic.detail import SingleObjectMixin from django.views.generic.detail import SingleObjectTemplateResponseMixin from django.views.generic.edit import FormMixin from django.views.generic.edit import ProcessFormView 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') Post = get_model('forum_conversation', 'Post') Topic = get_model('forum_conversation', 'Topic') TopicMoveForm = get_class('forum_moderation.forms', 'TopicMoveForm') PermissionRequiredMixin = get_class('forum_permission.viewmixins', 'PermissionRequiredMixin') class TopicLockView(PermissionRequiredMixin, SingleObjectTemplateResponseMixin, BaseDetailView): """ A view providing the ability to lock forum topics. """ template_name = 'forum_moderation/topic_lock.html' context_object_name = 'topic' success_message = _('This topic has been locked successfully.') model = Topic
# 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): """ Allows to retrieve a forum attachment. """ 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'
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 verifications on forums. It uses the ``ForumPermissionChecker`` class to perform these verifications. """ def __init__(self): # This dictionary will store the forums that are granted for a specific lit of permission
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') class TopicView(PermissionRequiredMixin, ListView): """ Displays a forum topic. """ template_name = 'forum_conversation/topic_detail.html'
from django.conf import settings from django.contrib.auth.models import Group from django.core.exceptions import ValidationError from django.db import models from django.utils.functional import cached_property from django.utils.translation import ugettext_lazy as _ from machina.core.loading import get_class PermissionConfig = get_class('forum_permission.defaults', 'PermissionConfig') class AbstractForumPermission(models.Model): """ Represents a single forum permission. The models that subclass ``AbstractForumPermission`` can be used to define forum permissions. A forum permission is basically defined by a codename and some booleans indicating if the considered permission can be granted globally (in that case the permission applies to all forums) or not. """ codename = models.CharField( max_length=150, verbose_name=_('Permission codename'), unique=True, db_index=True) is_global = models.BooleanField( verbose_name=_('Global permission'), help_text=_('This permission can be granted globally to all the forums'), default=False, db_index=True) is_local = models.BooleanField(
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): self._granted_forums_cache = {} self._user_perm_checkers_cache = {} # Filtering methods # --
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 ForumReadTrackFactory from machina.test.factories import GroupFactory from machina.test.factories import PostFactory from machina.test.factories import UserFactory from machina.test.testcases import BaseClientTestCase faker = FakerFactory.create() Forum = get_model('forum', 'Forum') PermissionHandler = get_class('forum_permission.handler', 'PermissionHandler') assign_perm = get_class('forum_permission.shortcuts', 'assign_perm') TrackingHandler = get_class('forum_tracking.handler', 'TrackingHandler') class TestMarkForumsReadView(BaseClientTestCase): @pytest.fixture(autouse=True) def setup(self): # Add some users self.u1 = UserFactory.create() self.u2 = UserFactory.create() self.g1 = GroupFactory.create() self.u1.groups.add(self.g1) self.u2.groups.add(self.g1) self.user.groups.add(self.g1)
from django.views.generic import DeleteView, DetailView, ListView from django.views.generic.detail import ( BaseDetailView, SingleObjectMixin, SingleObjectTemplateResponseMixin ) from django.views.generic.edit import FormMixin, ProcessFormView 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') Post = get_model('forum_conversation', 'Post') Topic = get_model('forum_conversation', 'Topic') TopicMoveForm = get_class('forum_moderation.forms', 'TopicMoveForm') PermissionRequiredMixin = get_class('forum_permission.viewmixins', 'PermissionRequiredMixin') class TopicLockView(PermissionRequiredMixin, SingleObjectTemplateResponseMixin, BaseDetailView): """ Provides the ability to lock forum topics. """ context_object_name = 'topic' model = Topic success_message = _('This topic has been locked successfully.') template_name = 'forum_moderation/topic_lock.html' def lock(self, request, *args, **kwargs): """ Locks the considered topic and retirects the user to the success URL. """ self.object = self.get_object()
from django.db import models from machina.core.loading import get_class ForumVisibilityContentTree = get_class('forum.visibility', 'ForumVisibilityContentTree') class ForumReadTrackManager(models.Manager): """ Provides useful manager methods for the ``ForumReadTrack`` model. """ def get_unread_forums_from_list(self, forums, user): """ Filter a list of forums and return only those which are unread. Given a list of forums find and returns the list of forums that are unread for the passed user. If a forum is unread all of its ancestors are also unread and will be included in the final list. """ unread_forums = [] visibility_contents = ForumVisibilityContentTree.from_forums(forums) forum_ids_to_visibility_nodes = visibility_contents.as_dict tracks = super().get_queryset().select_related('forum').filter( user=user, forum__in=forums) tracked_forums = [] for track in tracks: forum_last_post_on = forum_ids_to_visibility_nodes[ track.forum_id].last_post_on if (forum_last_post_on and track.mark_time < forum_last_post_on) \ and track.forum not in unread_forums: unread_forums.extend(
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 return kwargs def form_valid(self, form):
from django.views.generic import ListView from django.views.generic import TemplateView 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 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(TemplateView): """ Marks a set of forums as read. """ success_message = _('Forums have been marked read.') template_name = 'forum_tracking/mark_forums_read.html' @method_decorator(login_required) def dispatch(self, request, *args, **kwargs): return super(MarkForumsReadView,
from django.conf import settings from django.core.exceptions import ValidationError from django.db import models from django.db.models import Q from django.utils.encoding import force_text from django.utils.text import slugify from django.utils.translation import ugettext_lazy as _ from machina.conf import settings as machina_settings from machina.core import validators from machina.core.loading import get_class from machina.models.abstract_models import DatedModel from machina.models.fields import MarkupTextField ApprovedManager = get_class('forum_conversation.managers', 'ApprovedManager') class AbstractTopic(DatedModel): """ Represents a forum topic. """ forum = models.ForeignKey( 'forum.Forum', related_name='topics', on_delete=models.CASCADE, verbose_name=_('Topic forum'), ) poster = models.ForeignKey( settings.AUTH_USER_MODEL, blank=True, null=True, on_delete=models.CASCADE, verbose_name=_('Poster'), ) # The subject of the thread should correspond to the one associated with the first post.
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' paginate_by = machina_settings.PROFILE_POSTS_NUMBER_PER_PAGE template_name = 'forum_member/user_posts_list.html' user_pk_url_kwarg = 'pk' def get_context_data(self, **kwargs): """ Returns the context data to provide to the template. """ context = super().get_context_data(**kwargs)
""" Forum tracking signal receivers =============================== This module defines signal receivers. """ from django.dispatch import receiver from machina.core.loading import get_class topic_viewed = get_class('forum_conversation.signals', 'topic_viewed') @receiver(topic_viewed) def update_user_trackers(sender, topic, user, request, response, **kwargs): """ Receiver to mark a topic being viewed as read. This can result in marking the related forum tracker as read. """ TrackingHandler = get_class('forum_tracking.handler', 'TrackingHandler') # noqa track_handler = TrackingHandler() track_handler.mark_topic_read(topic, user)
# 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) response["Content-Disposition"] = "attachment; filename={}".format(filename)
from django.core.exceptions import ValidationError from django.db import models from django.db.models import Q from django.utils.encoding import force_text from django.utils.encoding import python_2_unicode_compatible from django.utils.text import slugify from django.utils.translation import ugettext_lazy as _ from machina.conf import settings as machina_settings from machina.core import validators from machina.core.loading import get_class from machina.models.abstract_models import DatedModel from machina.models.fields import MarkupTextField ApprovedManager = get_class('forum_conversation.managers', 'ApprovedManager') @python_2_unicode_compatible class AbstractTopic(DatedModel): """ Represents a forum topic. """ forum = models.ForeignKey( 'forum.Forum', related_name='topics', on_delete=models.CASCADE, verbose_name=_('Topic forum')) poster = models.ForeignKey( settings.AUTH_USER_MODEL, blank=True, null=True, on_delete=models.CASCADE, verbose_name=_('Poster'), ) # The subject of the thread should correspond to the one associated with the first post
# -*- 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
# Third party imports import pytest # Local application / specific library imports from machina.apps.forum.signals import forum_viewed from machina.core.db.models import get_model from machina.core.loading import get_class from machina.test.context_managers import mock_signal_receiver from machina.test.factories import create_forum from machina.test.factories import create_link_forum from machina.test.testcases import BaseClientTestCase 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') remove_perm = get_class('forum_permission.shortcuts', 'remove_perm') class TestForumView(BaseClientTestCase): @pytest.fixture(autouse=True) def setup(self): # Permission handler self.perm_handler = PermissionHandler() # Set up a top-level forum and a link forum self.top_level_forum = create_forum() self.top_level_link = create_link_forum(link_redirects=True) # Assign some permissions
import pytest from machina.core.loading import get_class from machina.test.factories import UserFactory get_forum_member_display_name = get_class('forum_member.shortcuts', 'get_forum_member_display_name') @pytest.mark.django_db class TestGetForumMemberDisplayNameShortcut: def test_returns_the_display_name_of_a_specific_user(self): user = UserFactory.create() assert get_forum_member_display_name(user) == user.username
""" 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): """ Allows to create or update forum posts. """ class Meta: model = Post fields = [ 'subject', 'content', 'username',