diff --git a/readthedocs/comments/__init__.py b/readthedocs/comments/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/readthedocs/comments/admin.py b/readthedocs/comments/admin.py deleted file mode 100644 index debfb776022..00000000000 --- a/readthedocs/comments/admin.py +++ /dev/null @@ -1,25 +0,0 @@ -"""ModelAdmin configurations for comments app.""" - -from __future__ import absolute_import -from django.contrib import admin -from .models import DocumentNode, DocumentComment, NodeSnapshot - - -class SnapshotAdmin(admin.TabularInline): - model = NodeSnapshot - - -class DocumentNodeAdmin(admin.ModelAdmin): - search_fields = ('id', 'document') - list_filter = ('project__name',) - raw_id_fields = ('project', 'version') - list_display = ('latest_hash', 'latest_commit') - inlines = (SnapshotAdmin,) - - -class DocumentCommentAdmin(admin.ModelAdmin): - search_fields = ('text',) - raw_id_fields = ('node',) - -admin.site.register(DocumentNode, DocumentNodeAdmin) -admin.site.register(DocumentComment, DocumentCommentAdmin) diff --git a/readthedocs/comments/backend.py b/readthedocs/comments/backend.py deleted file mode 100644 index f2d26deb64f..00000000000 --- a/readthedocs/comments/backend.py +++ /dev/null @@ -1,37 +0,0 @@ -"""Storage backends for the comments app.""" - -from __future__ import absolute_import -import json - -from django.core import serializers -from sphinx.websupport.storage import StorageBackend - -from .models import DocumentNode - - -class DjangoStorage(StorageBackend): - - """A Sphinx StorageBackend using Django.""" - - def get_metadata(self, docname, moderator=None): - ret_dict = {} - for node in DocumentNode.objects.filter(page=docname): - ret_dict[node.latest_hash()] = node.comments.count() - return ret_dict - - def get_data(self, node_id, username, moderator=None): - try: - node = DocumentNode.objects.get(snapshots__hash=node_id) - except DocumentNode.DoesNotExist: - return None - ret_comments = [] - for comment in node.comments.all(): - json_data = json.loads(serializers.serialize("json", [comment]))[0] - fields = json_data['fields'] - fields['pk'] = json_data['pk'] - ret_comments.append( - fields - ) - - return {'source': '', - 'comments': ret_comments} diff --git a/readthedocs/comments/migrations/0001_initial.py b/readthedocs/comments/migrations/0001_initial.py deleted file mode 100644 index 5a2d8c0a8f1..00000000000 --- a/readthedocs/comments/migrations/0001_initial.py +++ /dev/null @@ -1,83 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - -from __future__ import absolute_import -from django.db import models, migrations -from django.conf import settings - - -class Migration(migrations.Migration): - - dependencies = [ - ('builds', '0001_initial'), - ('projects', '0002_add_importedfile_model'), - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ] - - operations = [ - migrations.CreateModel( - name='DocumentComment', - fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('date', models.DateTimeField(auto_now_add=True, verbose_name='Date')), - ('rating', models.IntegerField(default=0, verbose_name='Rating')), - ('text', models.TextField(verbose_name='Text')), - ], - ), - migrations.CreateModel( - name='DocumentNode', - fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('page', models.CharField(max_length=255, verbose_name='Path')), - ('raw_source', models.TextField(verbose_name='Raw Source')), - ('project', models.ForeignKey(related_name='nodes', verbose_name='Project', to='projects.Project', null=True)), - ('version', models.ForeignKey(related_name='nodes', verbose_name='Version', to='builds.Version', null=True)), - ], - ), - migrations.CreateModel( - name='ModerationAction', - fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('decision', models.IntegerField(choices=[(0, b'No Decision'), (1, b'Publish'), (2, b'Hide')])), - ('date', models.DateTimeField(auto_now_add=True, verbose_name='Date')), - ('comment', models.ForeignKey(related_name='moderation_actions', to='comments.DocumentComment')), - ('user', models.ForeignKey(to=settings.AUTH_USER_MODEL)), - ], - options={ - 'get_latest_by': 'date', - }, - ), - migrations.CreateModel( - name='ModerationActionManager', - fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ], - ), - migrations.CreateModel( - name='NodeSnapshot', - fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('date', models.DateTimeField(auto_now_add=True, verbose_name=b'Publication date')), - ('hash', models.CharField(max_length=255, verbose_name='Hash')), - ('commit', models.CharField(max_length=255)), - ('node', models.ForeignKey(related_name='snapshots', to='comments.DocumentNode')), - ], - options={ - 'get_latest_by': 'date', - }, - ), - migrations.AddField( - model_name='documentcomment', - name='node', - field=models.ForeignKey(related_name='comments', to='comments.DocumentNode'), - ), - migrations.AddField( - model_name='documentcomment', - name='user', - field=models.ForeignKey(to=settings.AUTH_USER_MODEL), - ), - migrations.AlterUniqueTogether( - name='nodesnapshot', - unique_together=set([('hash', 'node', 'commit')]), - ), - ] diff --git a/readthedocs/comments/migrations/__init__.py b/readthedocs/comments/migrations/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/readthedocs/comments/models.py b/readthedocs/comments/models.py deleted file mode 100644 index cc15734e159..00000000000 --- a/readthedocs/comments/models.py +++ /dev/null @@ -1,244 +0,0 @@ -"""Models for the comments app.""" - -from __future__ import absolute_import -from builtins import str -from builtins import object -from django.contrib.auth.models import User -from django.db import models -from django.utils.encoding import python_2_unicode_compatible -from django.utils.translation import ugettext_lazy as _ -from rest_framework import serializers - -from readthedocs.restapi.serializers import VersionSerializer - - -class DocumentNodeManager(models.Manager): - - def create(self, *args, **kwargs): - - try: - node_hash = kwargs.pop('hash') - commit = kwargs.pop('commit') - except KeyError: - raise TypeError("You must provide a hash and commit for the initial NodeSnapshot.") - - node = super(DocumentNodeManager, self).create(*args, **kwargs) - NodeSnapshot.objects.create(commit=commit, hash=node_hash, node=node) - - return node - - def from_hash(self, version_slug, page, node_hash, project_slug=None): - """Return a node matching a given hash.""" - snapshots = NodeSnapshot.objects.filter(hash=node_hash, - node__version__slug=version_slug, - node__page=page) - - if project_slug: - snapshots = snapshots.filter(node__project__slug=project_slug) - - if not snapshots.exists(): - raise DocumentNode.DoesNotExist( - "No node exists on %s with a current hash of %s" % ( - page, node_hash)) - - if snapshots.count() == 1: - # If we have found only one snapshot, we know we have the correct node. - node = snapshots[0].node - else: - # IF we have found more than one snapshot... - number_of_nodes = len(set(snapshots.values_list('node'))) - if number_of_nodes == 1: - # ...and they're all from the same node, then we know we have the proper node. - node = snapshots[0].node - else: - # On the other hand, if they're from different nodes, then we must - # have different nodes with the same hash (and thus the same content). - raise NotImplementedError( - ''' - There is more than one node with this content on this page. - In the future, ReadTheDocs will implement an indexing feature - to allow unique identification of nodes on the same page with the same content. - ''') - return node - - -@python_2_unicode_compatible -class DocumentNode(models.Model): - - """Document node.""" - - objects = DocumentNodeManager() - - project = models.ForeignKey('projects.Project', verbose_name=_('Project'), - related_name='nodes', null=True) - version = models.ForeignKey('builds.Version', verbose_name=_('Version'), - related_name='nodes', null=True) - page = models.CharField(_('Path'), max_length=255) - - raw_source = models.TextField(_('Raw Source')) - - def __str__(self): - return "node %s on %s for %s" % (self.id, self.page, self.project) - - def latest_hash(self): - return self.snapshots.latest().hash - - def latest_commit(self): - return self.snapshots.latest().commit - - def visible_comments(self): - if not self.project.comment_moderation: - return self.comments.all() - # non-optimal SQL warning. - decisions = ModerationAction.objects.filter( - comment__node=self, - decision=1, - date__gt=self.snapshots.latest().date - ) - valid_comments = self.comments.filter(moderation_actions__in=decisions).distinct() - return valid_comments - - def update_hash(self, new_hash, commit): - latest_snapshot = self.snapshots.latest() - if latest_snapshot.hash == new_hash and latest_snapshot.commit == commit: - return latest_snapshot - return self.snapshots.create(hash=new_hash, commit=commit) - - -class DocumentNodeSerializer(serializers.ModelSerializer): - version = VersionSerializer() - - current_hash = serializers.CharField(source='latest_hash') - last_commit = serializers.CharField(source='latest_commit') - snapshots_count = serializers.CharField(source='snapshots.count') - - class Meta(object): - model = DocumentNode - exclude = ('') - - -@python_2_unicode_compatible -class NodeSnapshot(models.Model): - date = models.DateTimeField('Publication date', auto_now_add=True) - hash = models.CharField(_('Hash'), max_length=255) - node = models.ForeignKey(DocumentNode, related_name="snapshots") - commit = models.CharField(max_length=255) - - class Meta(object): - get_latest_by = 'date' - # Snapshots are *almost* unique_together just for node and hash, - # but for the possibility that a node's hash might change and then change back - # in a later commit. - unique_together = ("hash", "node", "commit") - - def __str__(self): - return self.hash - - -# class DocumentCommentManager(models.Manager): -# -# def visible(self, inquiring_user=None, node=None): -# if node: -# -# decisions = ModerationAction.objects.filter( -# comment__node=node, -# decision=1, -# date__gt=self.snapshots.latest().date -# ) -# valid_comments = node.comments.filter(moderation_actions__in=decisions).distinct() -# -# if not self.project.comment_moderation: -# return self.comments.all() -# else: -# non-optimal SQL warning. -# -# return valid_comments - - -@python_2_unicode_compatible -class DocumentComment(models.Model): - - """Comment on a ``DocumentNode`` by a user.""" - - date = models.DateTimeField(_('Date'), auto_now_add=True) - rating = models.IntegerField(_('Rating'), default=0) - text = models.TextField(_('Text')) - user = models.ForeignKey(User) - node = models.ForeignKey(DocumentNode, related_name='comments') - - def __str__(self): - return "%s - %s" % (self.text, self.node) - - def get_absolute_url(self): - return "/%s" % self.node.latest_hash() - - def moderate(self, user, decision): - return self.moderation_actions.create(user=user, decision=decision) - - def has_been_approved_since_most_recent_node_change(self): - try: - latest_moderation_action = self.moderation_actions.latest() - except ModerationAction.DoesNotExist: - # If we have no moderation actions, obviously we're not approved. - return False - - most_recent_node_change = self.node.snapshots.latest().date - - if latest_moderation_action.date > most_recent_node_change: - # If we do have an approval action which is newer than the most recent change, - # we'll return True or False commensurate with its "approved" attribute. - return latest_moderation_action.approved() - return False - - def is_orphaned(self): - raise NotImplementedError('TODO') - - -class DocumentCommentSerializer(serializers.ModelSerializer): - node = DocumentNodeSerializer() - - class Meta(object): - model = DocumentComment - fields = ('date', 'user', 'text', 'node') - - def perform_create(self): - pass - - -@python_2_unicode_compatible -class ModerationActionManager(models.Model): - - def __str__(self): - return str(self.id) - - def current_approvals(self): - # pylint: disable=unused-variable - most_recent_change = self.comment.node.snapshots.latest().date # noqa - - -@python_2_unicode_compatible -class ModerationAction(models.Model): - user = models.ForeignKey(User) - comment = models.ForeignKey(DocumentComment, related_name="moderation_actions") - decision = models.IntegerField(choices=( - (0, 'No Decision'), - (1, 'Publish'), - (2, 'Hide'), - )) - date = models.DateTimeField(_('Date'), auto_now_add=True) - - def __str__(self): - return "%s - %s" % (self.user_id, self.get_decision_display()) - - class Meta(object): - get_latest_by = 'date' - - def approved(self): - return self.decision == 1 - - -class ModerationActionSerializer(serializers.ModelSerializer): - - class Meta(object): - model = ModerationAction - exclude = () diff --git a/readthedocs/comments/session.py b/readthedocs/comments/session.py deleted file mode 100644 index 16076de4e92..00000000000 --- a/readthedocs/comments/session.py +++ /dev/null @@ -1,16 +0,0 @@ -"""Authentication backends for DRF.""" - -from __future__ import absolute_import -from rest_framework.authentication import SessionAuthentication - - -class UnsafeSessionAuthentication(SessionAuthentication): - - def authenticate(self, request): - http_request = request._request # pylint: disable=protected-access - user = getattr(http_request, 'user', None) - - if not user or not user.is_active: - return None - - return (user, None) diff --git a/readthedocs/comments/static/_static/ajax-loader.gif b/readthedocs/comments/static/_static/ajax-loader.gif deleted file mode 100644 index 61faf8cab23..00000000000 Binary files a/readthedocs/comments/static/_static/ajax-loader.gif and /dev/null differ diff --git a/readthedocs/comments/static/_static/comment-bright.png b/readthedocs/comments/static/_static/comment-bright.png deleted file mode 100644 index 551517b8c83..00000000000 Binary files a/readthedocs/comments/static/_static/comment-bright.png and /dev/null differ diff --git a/readthedocs/comments/static/_static/comment-close.png b/readthedocs/comments/static/_static/comment-close.png deleted file mode 100644 index 09b54be46da..00000000000 Binary files a/readthedocs/comments/static/_static/comment-close.png and /dev/null differ diff --git a/readthedocs/comments/static/_static/comment.png b/readthedocs/comments/static/_static/comment.png deleted file mode 100644 index 92feb52b882..00000000000 Binary files a/readthedocs/comments/static/_static/comment.png and /dev/null differ diff --git a/readthedocs/comments/static/_static/down-pressed.png b/readthedocs/comments/static/_static/down-pressed.png deleted file mode 100644 index 6f7ad782782..00000000000 Binary files a/readthedocs/comments/static/_static/down-pressed.png and /dev/null differ diff --git a/readthedocs/comments/static/_static/down.png b/readthedocs/comments/static/_static/down.png deleted file mode 100644 index 3003a88770d..00000000000 Binary files a/readthedocs/comments/static/_static/down.png and /dev/null differ diff --git a/readthedocs/comments/static/_static/file.png b/readthedocs/comments/static/_static/file.png deleted file mode 100644 index d18082e397e..00000000000 Binary files a/readthedocs/comments/static/_static/file.png and /dev/null differ diff --git a/readthedocs/comments/static/_static/minus.png b/readthedocs/comments/static/_static/minus.png deleted file mode 100644 index da1c5620d10..00000000000 Binary files a/readthedocs/comments/static/_static/minus.png and /dev/null differ diff --git a/readthedocs/comments/static/_static/plus.png b/readthedocs/comments/static/_static/plus.png deleted file mode 100644 index b3cb37425ea..00000000000 Binary files a/readthedocs/comments/static/_static/plus.png and /dev/null differ diff --git a/readthedocs/comments/static/_static/up-pressed.png b/readthedocs/comments/static/_static/up-pressed.png deleted file mode 100644 index 8bd587afee2..00000000000 Binary files a/readthedocs/comments/static/_static/up-pressed.png and /dev/null differ diff --git a/readthedocs/comments/static/_static/up.png b/readthedocs/comments/static/_static/up.png deleted file mode 100644 index b94625680b4..00000000000 Binary files a/readthedocs/comments/static/_static/up.png and /dev/null differ diff --git a/readthedocs/comments/templates/base.html b/readthedocs/comments/templates/base.html deleted file mode 100644 index 6ebaf40297d..00000000000 --- a/readthedocs/comments/templates/base.html +++ /dev/null @@ -1,57 +0,0 @@ - - - -
- -