From c65720dd58b0b51419767d2ab61a0a40c7644d4c Mon Sep 17 00:00:00 2001 From: Shreya Date: Thu, 15 Feb 2018 21:30:41 +0530 Subject: [PATCH] Remove comments app readthedocs.comments.models.ModerationActionManager is unimplemented. This is a cleanup issue. Closes #2879 --- readthedocs/comments/__init__.py | 0 readthedocs/comments/admin.py | 25 -- readthedocs/comments/backend.py | 37 --- .../comments/migrations/0001_initial.py | 83 ------ readthedocs/comments/migrations/__init__.py | 0 readthedocs/comments/models.py | 244 ------------------ readthedocs/comments/session.py | 16 -- .../comments/static/_static/ajax-loader.gif | Bin 673 -> 0 bytes .../static/_static/comment-bright.png | Bin 3500 -> 0 bytes .../comments/static/_static/comment-close.png | Bin 3578 -> 0 bytes .../comments/static/_static/comment.png | Bin 3445 -> 0 bytes .../comments/static/_static/down-pressed.png | Bin 368 -> 0 bytes readthedocs/comments/static/_static/down.png | Bin 363 -> 0 bytes readthedocs/comments/static/_static/file.png | Bin 392 -> 0 bytes readthedocs/comments/static/_static/minus.png | Bin 199 -> 0 bytes readthedocs/comments/static/_static/plus.png | Bin 199 -> 0 bytes .../comments/static/_static/up-pressed.png | Bin 372 -> 0 bytes readthedocs/comments/static/_static/up.png | Bin 363 -> 0 bytes readthedocs/comments/templates/base.html | 57 ---- readthedocs/comments/templates/doc.html | 33 --- readthedocs/comments/templates/docbase.html | 57 ---- readthedocs/comments/tests.py | 17 -- readthedocs/comments/urls.py | 17 -- readthedocs/comments/views.py | 216 ---------------- 24 files changed, 802 deletions(-) delete mode 100644 readthedocs/comments/__init__.py delete mode 100644 readthedocs/comments/admin.py delete mode 100644 readthedocs/comments/backend.py delete mode 100644 readthedocs/comments/migrations/0001_initial.py delete mode 100644 readthedocs/comments/migrations/__init__.py delete mode 100644 readthedocs/comments/models.py delete mode 100644 readthedocs/comments/session.py delete mode 100644 readthedocs/comments/static/_static/ajax-loader.gif delete mode 100644 readthedocs/comments/static/_static/comment-bright.png delete mode 100644 readthedocs/comments/static/_static/comment-close.png delete mode 100644 readthedocs/comments/static/_static/comment.png delete mode 100644 readthedocs/comments/static/_static/down-pressed.png delete mode 100644 readthedocs/comments/static/_static/down.png delete mode 100644 readthedocs/comments/static/_static/file.png delete mode 100644 readthedocs/comments/static/_static/minus.png delete mode 100644 readthedocs/comments/static/_static/plus.png delete mode 100644 readthedocs/comments/static/_static/up-pressed.png delete mode 100644 readthedocs/comments/static/_static/up.png delete mode 100644 readthedocs/comments/templates/base.html delete mode 100644 readthedocs/comments/templates/doc.html delete mode 100644 readthedocs/comments/templates/docbase.html delete mode 100644 readthedocs/comments/tests.py delete mode 100644 readthedocs/comments/urls.py delete mode 100644 readthedocs/comments/views.py 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 61faf8cab23993bd3e1560bff0668bd628642330..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 673 zcmZ?wbhEHb6krfw_{6~Q|Nno%(3)e{?)x>&1u}A`t?OF7Z|1gRivOgXi&7IyQd1Pl zGfOfQ60;I3a`F>X^fL3(@);C=vM_KlFfb_o=k{|A33hf2a5d61U}gjg=>Rd%XaNQW zW@Cw{|b%Y*pl8F?4B9 zlo4Fz*0kZGJabY|>}Okf0}CCg{u4`zEPY^pV?j2@h+|igy0+Kz6p;@SpM4s6)XEMg z#3Y4GX>Hjlml5ftdH$4x0JGdn8~MX(U~_^d!Hi)=HU{V%g+mi8#UGbE-*ao8f#h+S z2a0-5+vc7MU$e-NhmBjLIC1v|)9+Im8x1yacJ7{^tLX(ZhYi^rpmXm0`@ku9b53aN zEXH@Y3JaztblgpxbJt{AtE1ad1Ca>{v$rwwvK(>{m~Gf_=-Ro7Fk{#;i~+{{>QtvI yb2P8Zac~?~=sRA>$6{!(^3;ZP0TPFR(G_-UDU(8Jl0?(IXu$~#4A!880|o%~Al1tN diff --git a/readthedocs/comments/static/_static/comment-bright.png b/readthedocs/comments/static/_static/comment-bright.png deleted file mode 100644 index 551517b8c83b76f734ff791f847829a760ad1903..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3500 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 A2LJ#7 diff --git a/readthedocs/comments/static/_static/comment.png b/readthedocs/comments/static/_static/comment.png deleted file mode 100644 index 92feb52b8824c6b0f59b658b1196c61de9162a95..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3445 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 diff --git a/readthedocs/comments/static/_static/down.png b/readthedocs/comments/static/_static/down.png deleted file mode 100644 index 3003a88770de3977d47a2ba69893436a2860f9e7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 363 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|*pj^6U4S$Y z{B+)352QE?JR*yM+OLB!qm#z$3ZNi+iKnkC`z>}xaV3tUZ$qnrLa#kt978NlpS`ru z&)HFc^}^>{UOEce+71h5nn>6&w6A!ieNbu1wh)UGh{8~et^#oZ1# z>T7oM=FZ~xXWnTo{qnXm$ZLOlqGswI_m2{XwVK)IJmBjW{J3-B3x@C=M{ShWt#fYS9M?R;8K$~YwlIqwf>VA7q=YKcwf2DS4Zj5inDKXXB1zl=(YO3ST6~rDq)&z z*o>z)=hxrfG-cDBW0G$!?6{M<$@{_4{m1o%Ub!naEtn|@^frU1tDnm{r-UW|!^@B8 diff --git a/readthedocs/comments/static/_static/file.png b/readthedocs/comments/static/_static/file.png deleted file mode 100644 index d18082e397e7e54f20721af768c4c2983258f1b4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 392 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt_f1s;*b z3=G`DAk4@xYmNj^kiEpy*OmP$HyOL$D9)yc9|lc|nKf<9@eUiWd>3GuTC!a5vdfWYEazjncPj5ZQX%+1 zt8B*4=d)!cdDz4wr^#OMYfqGz$1LDFF>|#>*O?AGil(WEs?wLLy{Gj2J_@opDm%`dlax3yA*@*N$G&*ukFv>P8+2CBWO(qz zD0k1@kN>hhb1_6`&wrCswzINE(evt-5C1B^STi2@PmdKI;Vst0PQB6!2kdN diff --git a/readthedocs/comments/static/_static/minus.png b/readthedocs/comments/static/_static/minus.png deleted file mode 100644 index da1c5620d10c047525a467a425abe9ff5269cfc2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 199 zcmeAS@N?(olHy`uVBq!ia0vp^+#t-s1SHkYJtzcHoCO|{#XvD(5N2eUHAey{$X?>< z>&kweokM_|(Po{+Q=kw>iEBiObAE1aYF-J$w=>iB1I2R$WLpMkF=>bh=@O1TaS?83{1OVknK< z>&kweokM`jkU7Va11Q8%;u=xnoS&PUnpeW`?aZ|OK(QcC7sn8Z%gHvy&v=;Q4jejg zV8NnAO`-4Z@2~&zopr02WF_WB>pF diff --git a/readthedocs/comments/static/_static/up-pressed.png b/readthedocs/comments/static/_static/up-pressed.png deleted file mode 100644 index 8bd587afee2fe38989383ff82010147ea56b93dd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 372 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|*pj^6U4S$Y z{B+)352QE?JR*yM+OLB!qm#z$3ZNi+iKnkC`z>}Z1|5lxjZvvUp)Z~;jv*GO&raT- z#pEb(tbY1#Ey4dH;Y+=wAPPMA->(Ug=YM6W%tgKtA zI`O=0Laf#Y-Y4f~`^K_)D_mvj{B=4?=t!I41ZLNlI~j_4kE*^nvF$)|>mH^X%(>6c z8XimFvvIAOoRJf!>6jzIa5w(S%7lxdZ{*qJxhxpj6S#UB!oTuMX^Z^6%)IfT_v-!3 z=PEaM_iSh6_`s$!$NaEMP6gw}xaYa3wv(2tRq1T=+jv*GO&raUx z$K)u`w*Tuor>1}ySNCesuPuG-8#b%jw0sn-5fpk^!623V@1GR6+<`78?&Rhov&jx6 z*R7KttIVGJ=8yH~|HhI(uB&NIpYp$LXT}M`Z)D=?%dxpN#UiKM#HZsJK4DUm#Y3a5!dMF634rTxz_l%hvABb z(=Pc<$5*Xj@eE$@$89c0_oa>Y5;`&;INvn7C-9xQbH92`*_(~*lcvS}m5Z2pGdgKc z>;tJC%=6B^QS*>ubT+QGD)v`9z&&Y`y-xHu*7vDC$|9@xfdY)d)78&qol`;+01iQm A<^TWy 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 @@ - - - - - - {% block title %}{% endblock %} - {% block css %} - {{ sg.css|safe }} - {% endblock %} - - {% block js %} - {{ sg.script|safe }} - {% endblock %} - - - {% block relbar1 %} - - {% endblock %} - -
-
-
-
- {% block body %}{% endblock %} -
-
-
- {% block sidebar %}{% endblock %} -
- - {% block relbar2 %}{% endblock %} - -{%- block footer %} - -{%- endblock %} - - - diff --git a/readthedocs/comments/templates/doc.html b/readthedocs/comments/templates/doc.html deleted file mode 100644 index fe33dad7f73..00000000000 --- a/readthedocs/comments/templates/doc.html +++ /dev/null @@ -1,33 +0,0 @@ -{% extends "docbase.html" %} - -{% block title %} - {{ document.title|striptags }} -{% endblock %} - -{% block css %} - {{ document.css|safe }} -{% endblock %} - -{% block js %} - {{ document.script|safe }} -{% endblock %} - -{% block relbar1 %} - {{ document.relbar|safe }} -{% endblock %} - -{% block body %} - {{ document.body|safe }} -{% endblock %} - -{% block content %} - {{ document.body|safe }} -{% endblock %} - -{% block sidebar %} - {{ document.sidebar|safe }} -{% endblock %} - -{% block relbar2 %} - {{ document.relbar|safe }} -{% endblock %} diff --git a/readthedocs/comments/templates/docbase.html b/readthedocs/comments/templates/docbase.html deleted file mode 100644 index 70832116bfe..00000000000 --- a/readthedocs/comments/templates/docbase.html +++ /dev/null @@ -1,57 +0,0 @@ - - - - - - {% block title %}{% endblock %} - {% block css %} - {{ sg.css|safe }} - {% endblock %} - - {% block js %} - {{ sg.script|safe }} - {% endblock %} - - - {% block relbar1 %} - - {% endblock %} - -
-
-
-
- {% block body %}{% endblock %} -
-
-
- {% block sidebar %}{% endblock %} -
- - {% block relbar2 %}{% endblock %} - -{% block footer %} - -{% endblock %} - - - diff --git a/readthedocs/comments/tests.py b/readthedocs/comments/tests.py deleted file mode 100644 index e585808adc4..00000000000 --- a/readthedocs/comments/tests.py +++ /dev/null @@ -1,17 +0,0 @@ -""" -This file demonstrates writing tests using the unittest module. These will pass -when you run "manage.py test". - -Replace this with more appropriate tests for your application. -""" - -from __future__ import absolute_import -from django.test import TestCase - - -class SimpleTest(TestCase): - def test_basic_addition(self): - """ - Tests that 1 + 1 always equals 2. - """ - self.assertEqual(1 + 1, 2) diff --git a/readthedocs/comments/urls.py b/readthedocs/comments/urls.py deleted file mode 100644 index 7567f37c51f..00000000000 --- a/readthedocs/comments/urls.py +++ /dev/null @@ -1,17 +0,0 @@ -"""URL configuration for comments app.""" - -from __future__ import absolute_import -from django.conf.urls import url - -from readthedocs.comments import views - -urlpatterns = [ - url(r'build', views.build, name='build'), - url(r'_has_node', views.has_node, name='has_node'), - url(r'_add_node', views.add_node, name='add_node'), - url(r'_update_node', views.update_node, name='update_node'), - url(r'_attach_comment', views.attach_comment, name='attach_comment'), - url(r'_get_metadata', views.get_metadata, name='get_metadata'), - url(r'_get_options', views.get_options, name='get_options'), - url(r'(?P.*)', views.serve_file, name='serve_file'), -] diff --git a/readthedocs/comments/views.py b/readthedocs/comments/views.py deleted file mode 100644 index 6c4a807fe34..00000000000 --- a/readthedocs/comments/views.py +++ /dev/null @@ -1,216 +0,0 @@ -# -*- coding: utf-8 -*- -"""Views for comments app.""" - -from __future__ import ( - absolute_import, division, print_function, unicode_literals) - -from django.contrib.auth.decorators import login_required -from django.shortcuts import render -from django.utils.decorators import method_decorator -from rest_framework import permissions, status -from rest_framework.decorators import ( - api_view, authentication_classes, detail_route, permission_classes, - renderer_classes) -from rest_framework.exceptions import ParseError -from rest_framework.renderers import JSONRenderer -from rest_framework.response import Response -from rest_framework.viewsets import ModelViewSet -from sphinx.websupport import WebSupport - -from readthedocs.comments.models import ( - DocumentComment, DocumentCommentSerializer, DocumentNode, - DocumentNodeSerializer, ModerationActionSerializer, NodeSnapshot) -from readthedocs.projects.models import Project -from readthedocs.restapi.permissions import CommentModeratorOrReadOnly - -from .backend import DjangoStorage -from .session import UnsafeSessionAuthentication - -storage = DjangoStorage() - -support = WebSupport( - srcdir='/Users/eric/projects/readthedocs.org/docs', - builddir='/Users/eric/projects/readthedocs.org/docs/_build/websupport', - datadir='/Users/eric/projects/readthedocs.org/docs/_build/websupport/data', - storage=storage, - docroot='websupport', -) - -######## -# called by javascript -######## - - -@api_view(['GET']) -@permission_classes([permissions.IsAuthenticatedOrReadOnly]) -@renderer_classes((JSONRenderer,)) -def get_options(request): # pylint: disable=unused-argument - base_opts = support.base_comment_opts - base_opts['addCommentURL'] = '/api/v2/comments/' - base_opts['getCommentsURL'] = '/api/v2/comments/' - return Response(base_opts) - - -@api_view(['GET']) -@permission_classes([permissions.IsAuthenticatedOrReadOnly]) -@renderer_classes((JSONRenderer,)) -def get_metadata(request): - """ - Check for get_metadata. - - GET: page - """ - document = request.GET.get('page', '') - return Response(storage.get_metadata(docname=document)) - - -@api_view(['GET', 'POST']) -@permission_classes([permissions.AllowAny]) -@authentication_classes([UnsafeSessionAuthentication]) -@renderer_classes((JSONRenderer,)) -def attach_comment(request): - comment_id = request.POST.get('comment', '') - comment = DocumentComment.objects.get(pk=comment_id) - - node_id = request.POST.get('node', '') - snapshot = NodeSnapshot.objects.get(hash=node_id) - comment.node = snapshot.node - - serialized_comment = DocumentCommentSerializer(comment) - return Response(serialized_comment.data) - - -####### -# Normal Views -####### - - -def build(request): # pylint: disable=unused-argument - support.build() - - -def serve_file(request, file): # pylint: disable=redefined-builtin - document = support.get_document(file) - - return render(request, 'doc.html', {'document': document}) - - -###### -# Called by Builder -###### - - -@api_view(['GET']) -@permission_classes([permissions.IsAuthenticatedOrReadOnly]) -def has_node(request): - """ - Checks to see if a node exists. - - GET: node_id - The node's ID to check - """ - node_id = request.GET.get('node_id', '') - exists = storage.has_node(node_id) - return Response({'exists': exists}) - - -@api_view(['GET', 'POST']) -@permission_classes([permissions.AllowAny]) -@authentication_classes([UnsafeSessionAuthentication]) -@renderer_classes((JSONRenderer,)) -def add_node(request): - post_data = request.data - project = Project.objects.get(slug=post_data['project']) - page = post_data.get('document', '') - node_hash = post_data.get('id', '') - version = post_data.get('version', '') - commit = post_data.get('commit', '') - project.add_node(node_hash, page, version=version, commit=commit) - return Response() - - -@api_view(['GET', 'POST']) -@permission_classes([permissions.AllowAny]) -@authentication_classes([UnsafeSessionAuthentication]) -@renderer_classes((JSONRenderer,)) -def update_node(request): - post_data = request.data - try: - old_hash = post_data['old_hash'] - new_hash = post_data['new_hash'] - commit = post_data['commit'] - project = post_data['project'] - version = post_data['version'] - page = post_data['page'] - - node = DocumentNode.objects.from_hash( - node_hash=old_hash, project_slug=project, version_slug=version, - page=page) - - node.update_hash(new_hash, commit) - return Response(DocumentNodeSerializer(node).data) - except KeyError: - return Response( - 'You must include new_hash and commit in POST payload to this view.', - status.HTTP_400_BAD_REQUEST) - - -class CommentViewSet(ModelViewSet): - - """Viewset for Comment model.""" - - serializer_class = DocumentCommentSerializer - permission_classes = [ - CommentModeratorOrReadOnly, - permissions.IsAuthenticatedOrReadOnly, - ] - - def get_queryset(self): - qp = self.request.query_params - if qp.get('node'): - try: - node = DocumentNode.objects.from_hash( - version_slug=qp['version'], - page=qp['document_page'], - node_hash=qp['node'], - project_slug=qp['project'], - ) - queryset = DocumentComment.objects.filter(node=node) - - except KeyError: - raise ParseError( - 'To get comments by node, you must also provide page, ' - 'version, and project.') - except DocumentNode.DoesNotExist: - queryset = DocumentComment.objects.none() - elif qp.get('project'): - queryset = DocumentComment.objects.filter( - node__project__slug=qp['project']) - - else: - queryset = DocumentComment.objects.all() - return queryset - - @method_decorator(login_required) - def create(self, request, *args, **kwargs): - project = Project.objects.get(slug=request.data['project']) - comment = project.add_comment( - version_slug=request.data['version'], - page=request.data['document_page'], - content_hash=request.data['node'], - commit=request.data['commit'], - user=request.user, - text=request.data['text'], - ) - - serializer = self.get_serializer(comment) - headers = self.get_success_headers(serializer.data) - return Response( - serializer.data, status=status.HTTP_201_CREATED, headers=headers) - - @detail_route(methods=['put']) - def moderate(self, request, pk): # pylint: disable=unused-argument - comment = self.get_object() - decision = request.data['decision'] - moderation_action = comment.moderate(request.user, decision) - - return Response(ModerationActionSerializer(moderation_action).data)