From 3fa7792744e0dbc1c8e1937977a066a18e45e016 Mon Sep 17 00:00:00 2001 From: Shreya Date: Thu, 15 Feb 2018 21:30:41 +0530 Subject: [PATCH 1/5] 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) From 186351e8eda07f4dc5d4882d11b312bfbbbfcc98 Mon Sep 17 00:00:00 2001 From: Santos Gallegos Date: Wed, 14 Mar 2018 18:06:26 -0500 Subject: [PATCH 2/5] Remove comment app from code --- readthedocs/projects/models.py | 60 --- readthedocs/restapi/urls.py | 2 - readthedocs/rtd_tests/tests/test_comments.py | 467 ------------------ .../rtd_tests/tests/test_privacy_urls.py | 5 - readthedocs/settings/base.py | 1 - readthedocs/urls.py | 1 - 6 files changed, 536 deletions(-) delete mode 100644 readthedocs/rtd_tests/tests/test_comments.py diff --git a/readthedocs/projects/models.py b/readthedocs/projects/models.py index c4249351e84..f8f88140a6c 100644 --- a/readthedocs/projects/models.py +++ b/readthedocs/projects/models.py @@ -814,66 +814,6 @@ def add_subproject(self, child, alias=None): def remove_subproject(self, child): ProjectRelationship.objects.filter(parent=self, child=child).delete() - def moderation_queue(self): - # non-optimal SQL warning. - from readthedocs.comments.models import DocumentComment - queue = [] - comments = DocumentComment.objects.filter(node__project=self) - for comment in comments: - if not comment.has_been_approved_since_most_recent_node_change(): - queue.append(comment) - - return queue - - def add_node(self, content_hash, page, version, commit): - """ - Add comment node. - - :param content_hash: Hash of node content - :param page: Doc page for node - :param version: Slug for project version to apply node to - :type version: str - :param commit: Commit that node was updated in - :type commit: str - """ - from readthedocs.comments.models import NodeSnapshot, DocumentNode - project_obj = Project.objects.get(slug=self.slug) - version_obj = project_obj.versions.get(slug=version) - try: - NodeSnapshot.objects.get(hash=content_hash, node__project=project_obj, - node__version=version_obj, node__page=page, - commit=commit) - return False # ie, no new node was created. - except NodeSnapshot.DoesNotExist: - DocumentNode.objects.create( - hash=content_hash, - page=page, - project=project_obj, - version=version_obj, - commit=commit - ) - return True # ie, it's True that a new node was created. - - def add_comment(self, version_slug, page, content_hash, commit, user, text): - """ - Add comment to node. - - :param version_slug: Version slug to use for node lookup - :param page: Page to attach comment to - :param content_hash: Hash of content to apply comment to - :param commit: Commit that updated comment - :param user: :py:class:`User` instance that created comment - :param text: Comment text - """ - from readthedocs.comments.models import DocumentNode - try: - node = self.nodes.from_hash(version_slug, page, content_hash) - except DocumentNode.DoesNotExist: - version = self.versions.get(slug=version_slug) - node = self.nodes.create(version=version, page=page, - hash=content_hash, commit=commit) - return node.comments.create(user=user, text=text) - @property def features(self): return Feature.objects.for_project(self) diff --git a/readthedocs/restapi/urls.py b/readthedocs/restapi/urls.py index 5480ce98093..51fc72e17c6 100644 --- a/readthedocs/restapi/urls.py +++ b/readthedocs/restapi/urls.py @@ -7,7 +7,6 @@ from rest_framework import routers from readthedocs.constants import pattern_opts -from readthedocs.comments.views import CommentViewSet from readthedocs.restapi import views from readthedocs.restapi.views import ( core_views, footer_views, search_views, task_views, integrations @@ -33,7 +32,6 @@ r'remote/repo', RemoteRepositoryViewSet, base_name='remoterepository') router.register( r'remote/account', SocialAccountViewSet, base_name='remoteaccount') -router.register(r'comments', CommentViewSet, base_name="comments") urlpatterns = [ url(r'^', include(router.urls)), diff --git a/readthedocs/rtd_tests/tests/test_comments.py b/readthedocs/rtd_tests/tests/test_comments.py deleted file mode 100644 index 46ef5627bce..00000000000 --- a/readthedocs/rtd_tests/tests/test_comments.py +++ /dev/null @@ -1,467 +0,0 @@ -from __future__ import absolute_import -import random -from unittest.case import expectedFailure - -from django.contrib.auth.models import User -from django.test import TestCase -from django.test.client import RequestFactory -from django_dynamic_fixture import fixture -from django_dynamic_fixture import get -from django_dynamic_fixture import new -from rest_framework.test import APIRequestFactory, APITestCase - -from readthedocs.builds.models import Version -from readthedocs.comments.models import DocumentNode, DocumentComment -from readthedocs.comments.models import NodeSnapshot -from readthedocs.comments.views import add_node, get_metadata, update_node -from readthedocs.projects.models import Project -from readthedocs.projects.views.private import project_comments_moderation -from readthedocs.rtd_tests.utils import create_user - - -def create_node(hash=None, commit=None, **kwargs): - snapshot_kwargs = {} - if hash is not None: - snapshot_kwargs['hash'] = hash - if commit is not None: - snapshot_kwargs['commit'] = commit - node = get(DocumentNode, **kwargs) - get(NodeSnapshot, node=node, **snapshot_kwargs) - return node - - -class ModerationTests(TestCase): - @classmethod - def setUpTestData(cls): - cls.owner = create_user(username='owner', password='test') - - cls.moderated_project = get(Project, comment_moderation=True) - cls.moderated_project.users.add(cls.owner) - - cls.moderated_node = create_node(project=cls.moderated_project) - - cls.first_moderated_comment = get(DocumentComment, - node=cls.moderated_node) - cls.second_moderated_comment = get(DocumentComment, - node=cls.moderated_node) - - cls.unmoderated_project = get(Project, comment_moderation=False) - cls.unmoderated_project.users.add(cls.owner) - - cls.unmoderated_node = create_node(project=cls.unmoderated_project) - - cls.first_unmoderated_comment = get(DocumentComment, - node=cls.unmoderated_node) - cls.second_unmoderated_comment = get(DocumentComment, - node=cls.unmoderated_node) - - def test_approved_comments(self): - c = self.first_unmoderated_comment - - # This comment has never been approved... - self.assertFalse(c.has_been_approved_since_most_recent_node_change()) - - # ...until now! - c.moderate(user=self.owner, decision=1) - self.assertTrue(c.has_been_approved_since_most_recent_node_change()) - - def test_new_node_snapshot_causes_comment_to_show_as_not_approved_since_change(self): - - c = self.first_unmoderated_comment - c.moderate(user=self.owner, decision=1) - - self.assertTrue(c.has_been_approved_since_most_recent_node_change()) - c.node.snapshots.create(hash=random.getrandbits(128)) - self.assertFalse(c.has_been_approved_since_most_recent_node_change()) - - def test_unmoderated_project_shows_all_comments(self): - - visible_comments = self.unmoderated_node.visible_comments() - - self.assertIn(self.first_unmoderated_comment, visible_comments) - self.assertIn(self.second_unmoderated_comment, visible_comments) - - def test_unapproved_comment_is_not_visible_on_moderated_project(self): - - # We take a look at the visible comments and find that neither comment - # is among them. - visible_comments = self.moderated_node.visible_comments() - self.assertNotIn(self.first_moderated_comment, visible_comments) - self.assertNotIn(self.second_moderated_comment, visible_comments) - - def test_moderated_project_with_unchanged_nodes_shows_only_approved_comment(self): - # Approve the first comment... - self.first_moderated_comment.moderate(user=self.owner, decision=1) - - # ...and find that the first comment, but not the second one, is visible. - visible_comments = self.moderated_node.visible_comments() - self.assertIn(self.first_moderated_comment, visible_comments) - self.assertNotIn(self.second_moderated_comment, visible_comments) - - def test_moderated_project_with_changed_nodes_dont_show_comments_that_havent_been_approved_since(self): - # Approve the first comment... - self.first_moderated_comment.moderate(user=self.owner, decision=1) - - # ...but this time, change the node. - self.first_moderated_comment.node.snapshots.create(hash=random.getrandbits(128)) - - # Now it does not show as visible. - visible_comments = self.moderated_node.visible_comments() - self.assertNotIn(self.first_moderated_comment, visible_comments) - - def test_unapproved_comments_appear_in_moderation_queue(self): - queue = self.moderated_project.moderation_queue() - self.assertIn(self.first_moderated_comment, queue) - self.assertIn(self.second_moderated_comment, queue) - - def test_approved_comments_do_not_appear_in_moderation_queue(self): - self.first_moderated_comment.moderate(user=self.owner, decision=1) - queue = self.moderated_project.moderation_queue() - self.assertNotIn(self.first_moderated_comment, queue) - self.assertIn(self.second_moderated_comment, queue) - - -class NodeAndSnapshotTests(TestCase): - - def test_update_with_same_hash_does_not_create_new_snapshot(self): - node = get(DocumentNode) - get(NodeSnapshot, node=node) - - hash = "SOMEHASH" - commit = "SOMEGITCOMMIT" - - # We initially have just one snapshot. - self.assertEqual(node.snapshots.count(), 1) - - # ...but when we update the hash, we have two. - node.update_hash(hash, commit) - self.assertEqual(node.snapshots.count(), 2) - - # If we update with the same exact hash and commit, it doesn't create a new snapshot. - node.update_hash(hash, commit) - self.assertEqual(node.snapshots.count(), 2) - - def test_node_cannot_be_created_without_commit_and_hash(self): - project = get(Project, versions=[fixture()]) - some_version = project.versions.all()[0] - - self.assertRaises(TypeError, - DocumentNode.objects.create, - project=project, - version=some_version, - hash=random.getrandbits(128) - ) - - self.assertRaises(TypeError, - DocumentNode.objects.create, - project=project, - version=some_version, - commit=random.getrandbits(128) - ) - - def test_node_can_be_sought_From_new_hash(self): - - first_hash = "THEoriginalHASH" - second_hash = 'ANEWCRAZYHASH' - - node = create_node(hash=first_hash) - get(DocumentComment) - node.update_hash(second_hash, 'ANEWCRAZYCOMMIT') - - node_from_orm = DocumentNode.objects.from_hash(node.version.slug, - node.page, - node.latest_hash(), - project_slug=node.project.slug) - self.assertEqual(node, node_from_orm) - - node.update_hash(first_hash, 'AthirdCommit') - - node_from_orm2 = DocumentNode.objects.from_hash(node.version.slug, node.page, first_hash, node.project.slug) - self.assertEqual(node, node_from_orm2) - - @expectedFailure - def test_nodes_with_same_hash_oddness(self): - - node_hash = "AcommonHASH" - page = "somepage" - commit = "somecommit" - project = get(Project, versions=[fixture()]) - - project.add_node(node_hash=node_hash, - page=page, - version=project.versions.all()[0].slug, - commit=commit, - ) - - # A new commit with a second instance of the exact same content. - project.add_node(node_hash=node_hash, - page=page, - version=project.versions.all()[0].slug, - commit="ANEWCOMMIT", - ) - try: - project.nodes.from_hash(project.versions.all()[0].slug, page, node_hash, project.slug) - except NotImplementedError: - self.fail("We don't have indexing yet.") - - -class CommentModerationViewsTests(TestCase): - @classmethod - def setUpTestData(cls): - cls.owner = create_user(username='owner', password='test') - - cls.moderated_project = get(Project, comment_moderation=True) - cls.moderated_project.users.add(cls.owner) - - cls.moderated_node = get(DocumentNode, - project=cls.moderated_project) - get(NodeSnapshot, node=cls.moderated_node) - - cls.moderated_comment = get(DocumentComment, - text='Some comment text.', - node=cls.moderated_node) - - def test_unmoderated_comments_are_listed_in_view(self): - - request = RequestFactory() - request.user = self.owner - request.META = {} - response = project_comments_moderation(request, self.moderated_project.slug) - - self.assertContains(response, self.moderated_comment.text) - - -class CommentAPIViewsTests(APITestCase): - - request_factory = APIRequestFactory() - - @classmethod - def setUpTestData(cls): - cls.owner = create_user(username='owner', password='test') - - cls.moderated_project = get(Project, comment_moderation=True) - cls.moderated_project.users.add(cls.owner) - cls.moderated_version = get(Version, project=cls.moderated_project) - - cls.moderated_node = get(DocumentNode, - project=cls.moderated_project, - version=cls.moderated_version) - get(NodeSnapshot, node=cls.moderated_node) - - def test_get_comments_view(self): - - number_of_comments = DocumentComment.objects.count() - - response = self.client.get('/api/v2/comments/') - self.assertEqual(number_of_comments, response.data['count']) - - # moooore comments. - get(DocumentComment, n=50, node=self.moderated_node) - - response = self.client.get('/api/v2/comments/') - self.assertEqual(number_of_comments + 50, response.data['count']) - - def test_get_metadata_view(self): - - node = create_node() - - get_data = { - 'project': node.project.slug, - 'version': node.version.slug, - 'page': node.page - } - request = self.request_factory.get('/_get_metadata/', get_data) - response = get_metadata(request) - response.render() - - number_of_comments = response.data[node.latest_hash()] - - # There haven't been any comments yet. - self.assertEqual(number_of_comments, 0) - - # Now we'll make one. - get(DocumentComment, node=node, text="Our first comment!") - - second_request = self.request_factory.get('/_get_metadata/', get_data) - second_response = get_metadata(second_request) - second_response.render() - - number_of_comments = second_response.data[node.latest_hash()] - - # And sure enough - one comment. - self.assertEqual(number_of_comments, 1) - - def test_add_node_view(self): - - node = self.moderated_project.nodes.all()[0] - - post_data = { - 'document': node.page, - 'id': node.latest_hash(), - 'project': node.project.slug, - 'version': node.version.slug, - 'commit': node.latest_commit(), - } - - # Now let's delete the node.... - DocumentNode.objects.all().delete() - - # ...we have no nodes. - self.assertEqual(DocumentNode.objects.count(), 0) - - # Hit the API again. - request = self.request_factory.post('/_add_node/', post_data) - response = add_node(request) - - # We do now have exactly one Node. - self.assertEqual(DocumentNode.objects.count(), 1) - - def test_update_node_view(self): - - node = create_node() - - # Our node has one snapshot. - self.assertEqual(node.snapshots.count(), 1) - - new_hash = "CRAZYnewHASHtoUPDATEnode" - commit = "COOLNEWGITCOMMITHASH" - - post_data = { - 'old_hash': node.latest_hash(), - 'new_hash': new_hash, - 'commit': commit, - 'project': node.project.slug, - 'version': node.version.slug, - 'page': node.page - } - - request = self.request_factory.post('/_update_node/', post_data) - response = update_node(request) - response.render() - - self.assertEqual(response.data['current_hash'], new_hash) - - # We now have two snapshots. - self.assertEqual(node.snapshots.count(), 2) - # And the latest hash is the one we just set. - self.assertEqual(node.latest_hash(), new_hash) - - def test_add_comment_view_without_existing_hash(self): - - comment_text = "Here's a comment added to a new hash." - version = get(Version, project=fixture()) - node = create_node(project=version.project, version=version) - user = create_user(username='test', password='test') - - number_of_nodes = DocumentNode.objects.count() - - post_data = { - 'node': random.getrandbits(128), - 'commit': random.getrandbits(128), - 'project': node.project.slug, - 'version': node.version.slug, - 'document_page': node.page, - 'text': comment_text - } - - self.client.login(username="test", password="test") - - response = self.client.post('/api/v2/comments/', post_data) - self.assertEqual(response.status_code, 201) - self.assertEqual(response.data['text'], comment_text) - self.assertEqual(DocumentNode.objects.count(), number_of_nodes + 1) # We created a new node. - - def test_add_comment_view_with_existing_hash(self): - - node = create_node() - user = create_user(username='test', password='test') - - comment_text = "Here's a comment added through the comment view." - - post_data = { - 'node': node.latest_hash(), - 'commit': node.latest_hash(), - 'project': node.project.slug, - 'version': node.version.slug, - 'document_page': node.page, - 'text': comment_text - } - - self.client.login(username="test", password="test") - response = self.client.post('/api/v2/comments/', post_data) - - comment_from_orm = node.comments.filter(text=comment_text) - self.assertTrue(comment_from_orm.exists()) - - self.assertEqual(comment_from_orm[0].node, node, - "The comment exists, but lives in a different node! Not supposed to happen.") - - def test_add_comment_view_with_changed_hash(self): - - first_hash = "THEoriginalHASH" - second_hash = 'ANEWCRAZYHASH' - - comment_text = "This comment will follow its node despite hash changing." - - # Create a comment on a node whose latest hash is the first one. - node = create_node(hash=first_hash) - get(DocumentComment, node=node, text=comment_text) - - # Now change the node's hash. - node.update_hash(second_hash, 'ANEWCRAZYCOMMIT') - - node_from_orm = DocumentNode.objects.from_hash(version_slug=node.version.slug, - page=node.page, - node_hash=node.latest_hash(), - project_slug=node.project.slug) - - # It's the same node. - self.assertEqual(node, node_from_orm) - - # Get all the comments with the second hash. - query_params = {'node': second_hash, - 'document_page': node.page, - 'project': node.project.slug, - 'version': node.version.slug, - } - - response = self.client.get('/api/v2/comments/', query_params) - - self.assertEqual(response.data['results'][0]['text'], comment_text) - - def test_moderate_comment_by_approving(self): - user = create_user(username='test', password='test') - - project = get(Project, versions=[fixture()]) - project.users.add(user) - node = create_node(project=project) - - comment = get(DocumentComment, node=node) - - post_data = { - 'decision': 1, - } - - self.assertFalse(comment.has_been_approved_since_most_recent_node_change()) - - self.client.login(username="test", password="test") - response = self.client.put('/api/v2/comments/%s/moderate/' % comment.id, post_data) - self.assertEqual(response.data['decision'], 1) - self.assertTrue(comment.has_been_approved_since_most_recent_node_change()) - - def test_stranger_cannot_moderate_comments(self): - - node = create_node() - comment = get(DocumentComment, node=node) - - post_data = { - 'decision': 1, - } - - response = self.client.put('/api/v2/comments/%s/moderate/' % comment.id, - post_data - ) - - self.assertEqual(response.status_code, 403) - - test_retrieve_comment_on_old_hash = test_post_comment_on_old_hash = None diff --git a/readthedocs/rtd_tests/tests/test_privacy_urls.py b/readthedocs/rtd_tests/tests/test_privacy_urls.py index b8ec1350fc1..761a2eedc75 100644 --- a/readthedocs/rtd_tests/tests/test_privacy_urls.py +++ b/readthedocs/rtd_tests/tests/test_privacy_urls.py @@ -12,7 +12,6 @@ from taggit.models import Tag from readthedocs.builds.models import Build, VersionAlias, BuildCommandResult -from readthedocs.comments.models import DocumentComment, NodeSnapshot from readthedocs.core.utils.tasks import TaskNoPermission from readthedocs.integrations.models import HttpExchange, Integration from readthedocs.projects.models import Project, Domain @@ -294,8 +293,6 @@ def setUp(self): self.build = get(Build, project=self.pip) self.build_command_result = get(BuildCommandResult, project=self.pip) self.domain = get(Domain, url='http://docs.foobar.com', project=self.pip) - self.comment = get(DocumentComment, node__project=self.pip) - self.snapshot = get(NodeSnapshot, node=self.comment.node) self.social_account = get(SocialAccount) self.remote_org = get(RemoteOrganization) self.remote_repo = get(RemoteRepository, organization=self.remote_org) @@ -312,7 +309,6 @@ def setUp(self): 'buildcommandresult-detail': {'pk': self.build_command_result.pk}, 'version-detail': {'pk': self.pip.versions.all()[0].pk}, 'domain-detail': {'pk': self.domain.pk}, - 'comments-detail': {'pk': self.comment.pk}, 'footer_html': {'data': {'project': 'pip', 'version': 'latest', 'page': 'index'}}, 'remoteorganization-detail': {'pk': self.remote_org.pk}, 'remoterepository-detail': {'pk': self.remote_repo.pk}, @@ -324,7 +320,6 @@ def setUp(self): 'project-token': {'status_code': 403}, 'emailhook-list': {'status_code': 403}, 'emailhook-detail': {'status_code': 403}, - 'comments-moderate': {'status_code': 405}, 'embed': {'status_code': 400}, 'docurl': {'status_code': 400}, 'cname': {'status_code': 400}, diff --git a/readthedocs/settings/base.py b/readthedocs/settings/base.py index b4f7efcf7da..0f457c0efd5 100644 --- a/readthedocs/settings/base.py +++ b/readthedocs/settings/base.py @@ -90,7 +90,6 @@ def INSTALLED_APPS(self): # noqa 'readthedocs.bookmarks', 'readthedocs.projects', 'readthedocs.builds', - 'readthedocs.comments', 'readthedocs.core', 'readthedocs.doc_builder', 'readthedocs.oauth', diff --git a/readthedocs/urls.py b/readthedocs/urls.py index b6053ab1983..3c4341376be 100644 --- a/readthedocs/urls.py +++ b/readthedocs/urls.py @@ -63,7 +63,6 @@ url(r'^api/', include(v1_api.urls)), url(r'^api/v2/', include('readthedocs.restapi.urls')), url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')), - url(r'^websupport/', include('readthedocs.comments.urls')), ] i18n_urls = [ From aefa1b6067f87e2551d8a0e1254ec545b94008d4 Mon Sep 17 00:00:00 2001 From: Santos Gallegos Date: Wed, 14 Mar 2018 18:12:38 -0500 Subject: [PATCH 3/5] Add todo --- readthedocs/projects/models.py | 1 + 1 file changed, 1 insertion(+) diff --git a/readthedocs/projects/models.py b/readthedocs/projects/models.py index f8f88140a6c..6b9107f6884 100644 --- a/readthedocs/projects/models.py +++ b/readthedocs/projects/models.py @@ -136,6 +136,7 @@ class Project(models.Model): 'DirectoryHTMLBuilder">More info.')) # Project features + # TODO: remove this? allow_comments = models.BooleanField(_('Allow Comments'), default=False) comment_moderation = models.BooleanField( _('Comment Moderation'), default=False,) From a3feab79e8990766fd3e52e17e1495d7fbe83cee Mon Sep 17 00:00:00 2001 From: Santos Gallegos Date: Wed, 14 Mar 2018 19:21:37 -0500 Subject: [PATCH 4/5] Remove comment moderation --- readthedocs/projects/forms.py | 2 - readthedocs/projects/urls/private.py | 8 --- readthedocs/projects/views/private.py | 25 --------- readthedocs/rtd_tests/tests/test_views.py | 8 --- .../templates/core/project_bar_base.html | 1 - .../projects/project_comments_moderation.html | 33 ----------- .../projects/project_comments_settings.html | 56 ------------------- .../templates/projects/project_edit_base.html | 3 - 8 files changed, 136 deletions(-) delete mode 100644 readthedocs/templates/projects/project_comments_moderation.html delete mode 100644 readthedocs/templates/projects/project_comments_settings.html diff --git a/readthedocs/projects/forms.py b/readthedocs/projects/forms.py index fb261bd246c..6df32d20120 100644 --- a/readthedocs/projects/forms.py +++ b/readthedocs/projects/forms.py @@ -230,8 +230,6 @@ class Meta(object): 'repo', 'repo_type', # Extra - # 'allow_comments', - # 'comment_moderation', 'description', 'documentation_type', 'language', diff --git a/readthedocs/projects/urls/private.py b/readthedocs/projects/urls/private.py index 7033e71a566..1cdc294416d 100644 --- a/readthedocs/projects/urls/private.py +++ b/readthedocs/projects/urls/private.py @@ -36,10 +36,6 @@ private.project_manage, name='projects_manage'), - url(r'^(?P[-\w]+)/comments_moderation/$', - private.project_comments_moderation, - name='projects_comments_moderation'), - url(r'^(?P[-\w]+)/edit/$', ProjectUpdate.as_view(), name='projects_edit'), @@ -76,10 +72,6 @@ private.project_notifications, name='projects_notifications'), - url(r'^(?P[-\w]+)/comments/$', - private.project_comments_settings, - name='projects_comments'), - url(r'^(?P[-\w]+)/notifications/delete/$', private.project_notifications_delete, name='projects_notification_delete'), diff --git a/readthedocs/projects/views/private.py b/readthedocs/projects/views/private.py index c9d52748b2b..97121764e8e 100644 --- a/readthedocs/projects/views/private.py +++ b/readthedocs/projects/views/private.py @@ -84,17 +84,6 @@ def project_manage(__, project_slug): return HttpResponseRedirect(reverse('projects_detail', args=[project_slug])) -@login_required -def project_comments_moderation(request, project_slug): - project = get_object_or_404( - Project.objects.for_admin_user(request.user), slug=project_slug) - return render( - request, - 'projects/project_comments_moderation.html', - {'project': project}, - ) - - class ProjectUpdate(ProjectSpamMixin, PrivateViewMixin, UpdateView): form_class = UpdateProjectForm @@ -536,20 +525,6 @@ def project_notifications(request, project_slug): ) -@login_required -def project_comments_settings(request, project_slug): - project = get_object_or_404( - Project.objects.for_admin_user(request.user), slug=project_slug) - - return render( - request, - 'projects/project_comments_settings.html', - { - 'project': project, - }, - ) - - @login_required def project_notifications_delete(request, project_slug): """Project notifications delete confirmation view.""" diff --git a/readthedocs/rtd_tests/tests/test_views.py b/readthedocs/rtd_tests/tests/test_views.py index a3fdad5f4d8..c1bcf92303e 100644 --- a/readthedocs/rtd_tests/tests/test_views.py +++ b/readthedocs/rtd_tests/tests/test_views.py @@ -84,10 +84,6 @@ def test_projects_manage(self): response = self.client.get('/dashboard/pip/') self.assertRedirectToLogin(response) - def test_comments_moderation(self): - response = self.client.get('/dashboard/pip/comments_moderation/') - self.assertRedirectToLogin(response) - def test_edit(self): response = self.client.get('/dashboard/pip/edit/') self.assertRedirectToLogin(response) @@ -138,10 +134,6 @@ def test_project_notifications(self): response = self.client.get('/dashboard/pip/notifications/') self.assertRedirectToLogin(response) - def test_project_comments(self): - response = self.client.get('/dashboard/pip/comments/') - self.assertRedirectToLogin(response) - def test_project_notifications_delete(self): response = self.client.get('/dashboard/pip/notifications/delete/') self.assertRedirectToLogin(response) diff --git a/readthedocs/templates/core/project_bar_base.html b/readthedocs/templates/core/project_bar_base.html index 1224442eed4..c7063a8dc53 100644 --- a/readthedocs/templates/core/project_bar_base.html +++ b/readthedocs/templates/core/project_bar_base.html @@ -68,7 +68,6 @@

{% endcomment %} {% if request.user|is_admin:project %} -
  • {% trans "Admin" %}
  • {% endif %} diff --git a/readthedocs/templates/projects/project_comments_moderation.html b/readthedocs/templates/projects/project_comments_moderation.html deleted file mode 100644 index de5d1330deb..00000000000 --- a/readthedocs/templates/projects/project_comments_moderation.html +++ /dev/null @@ -1,33 +0,0 @@ -{% extends "projects/base_project.html" %} - -{% block body_class %}project_detail{% endblock %} - -{% block title %}{{ project.name }}{% endblock %} - -{% block project_editing %} - {% with comments_active="active" %} - {% include "core/project_bar.html" %} - {% endwith %} -{% endblock %} - -{% block content %} - -
    -
    -
    -
    -
      - {% for comment in project.moderation_queue %} -
    • - {{comment.user}}: {{comment.text}} (at {{comment.date}}) - Approve -
    • - {% endfor %} -
    -
    -
    - -
    -
    - -{% endblock %} diff --git a/readthedocs/templates/projects/project_comments_settings.html b/readthedocs/templates/projects/project_comments_settings.html deleted file mode 100644 index 7c85aaa6f28..00000000000 --- a/readthedocs/templates/projects/project_comments_settings.html +++ /dev/null @@ -1,56 +0,0 @@ -{% extends "projects/project_edit_base.html" %} - -{% load i18n %} - -{% block title %}{% trans "Comments Settings" %}{% endblock %} - -{% block nav-dashboard %} class="active"{% endblock %} - -{% block editing-option-comments %}class="active"{% endblock %} - -{% block project-comments-active %}active{% endblock %} -{% block project_edit_content_header %}{% trans "Comments Settings" %}{% endblock %} - -{% block project_edit_content %} -

    - {% trans "Settings for comments and moderation." %} -

    - -{% comment %} -

    {% trans "Existing Translations" %}

    -

    -

    -

    - {% trans "Choose which project you would like to add as a translation." %} -

    -
    {% csrf_token %} - {{ form.as_p }} -

    - -

    -
    -{% endblock %} - - -{% block footerjs %} - $('#id_project').autocomplete({ - source: '{% url "search_autocomplete" %}', - minLength: 2, - open: function(event, ui) { - ac_top = $('.ui-autocomplete').css('top'); - $('.ui-autocomplete').css({'width': '233px', 'top': ac_top + 10 }); - } - }); - -{% endcomment %} - - -{% endblock %} diff --git a/readthedocs/templates/projects/project_edit_base.html b/readthedocs/templates/projects/project_edit_base.html index 9dde399baff..bb94c50f44b 100644 --- a/readthedocs/templates/projects/project_edit_base.html +++ b/readthedocs/templates/projects/project_edit_base.html @@ -25,9 +25,6 @@
  • {% trans "Integrations" %}
  • {% trans "Notifications" %}
  • {% trans "Advertising" %}
  • - {% if project.allow_comments %} -
  • {% trans "Comments" %}
  • - {% endif %}

    {% block project_edit_content_header %}{% endblock %}

    From 6794a6e46df23048c2bdd3ecc596635dd6822586 Mon Sep 17 00:00:00 2001 From: Santos Gallegos Date: Wed, 14 Mar 2018 19:56:03 -0500 Subject: [PATCH 5/5] Remove allow_comments code --- readthedocs/doc_builder/backends/sphinx.py | 10 ++------- readthedocs/projects/admin.py | 4 ++-- readthedocs/rtd_tests/tests/test_builds.py | 26 ---------------------- 3 files changed, 4 insertions(+), 36 deletions(-) diff --git a/readthedocs/doc_builder/backends/sphinx.py b/readthedocs/doc_builder/backends/sphinx.py index 7e3d0914411..66154f68dea 100644 --- a/readthedocs/doc_builder/backends/sphinx.py +++ b/readthedocs/doc_builder/backends/sphinx.py @@ -214,10 +214,7 @@ class HtmlBuilder(BaseSphinx): def __init__(self, *args, **kwargs): super(HtmlBuilder, self).__init__(*args, **kwargs) - if self.project.allow_comments: - self.sphinx_builder = 'readthedocs-comments' - else: - self.sphinx_builder = 'readthedocs' + self.sphinx_builder = 'readthedocs' class HtmlDirBuilder(HtmlBuilder): @@ -225,10 +222,7 @@ class HtmlDirBuilder(HtmlBuilder): def __init__(self, *args, **kwargs): super(HtmlDirBuilder, self).__init__(*args, **kwargs) - if self.project.allow_comments: - self.sphinx_builder = 'readthedocsdirhtml-comments' - else: - self.sphinx_builder = 'readthedocsdirhtml' + self.sphinx_builder = 'readthedocsdirhtml' class SingleHtmlBuilder(HtmlBuilder): diff --git a/readthedocs/projects/admin.py b/readthedocs/projects/admin.py index fac08e3b087..7b6261af51a 100644 --- a/readthedocs/projects/admin.py +++ b/readthedocs/projects/admin.py @@ -102,8 +102,8 @@ class ProjectAdmin(GuardedModelAdmin): """Project model admin view.""" prepopulated_fields = {'slug': ('name',)} - list_display = ('name', 'slug', 'repo', 'repo_type', 'allow_comments', 'featured', 'theme') - list_filter = ('repo_type', 'allow_comments', 'featured', 'privacy_level', + list_display = ('name', 'slug', 'repo', 'repo_type', 'featured', 'theme') + list_filter = ('repo_type', 'featured', 'privacy_level', 'documentation_type', 'programming_language', ProjectOwnerBannedFilter) list_editable = ('featured',) diff --git a/readthedocs/rtd_tests/tests/test_builds.py b/readthedocs/rtd_tests/tests/test_builds.py index b53cd80b7ad..8f07156cfa3 100644 --- a/readthedocs/rtd_tests/tests/test_builds.py +++ b/readthedocs/rtd_tests/tests/test_builds.py @@ -129,32 +129,6 @@ def test_build_respects_yaml(self): # PDF however was disabled and therefore not built. self.assertFalse(self.mocks.pdf_build.called) - def test_builder_comments(self): - '''Normal build with comments''' - project = get(Project, - documentation_type='sphinx', - allow_comments=True, - versions=[fixture()]) - version = project.versions.all()[0] - build_env = LocalBuildEnvironment(version=version, project=project, build={}) - python_env = Virtualenv(version=version, build_env=build_env) - builder_class = get_builder_class(project.documentation_type) - builder = builder_class(build_env, python_env) - self.assertEqual(builder.sphinx_builder, 'readthedocs-comments') - - def test_builder_no_comments(self): - '''Test builder without comments''' - project = get(Project, - documentation_type='sphinx', - allow_comments=False, - versions=[fixture()]) - version = project.versions.all()[0] - build_env = LocalBuildEnvironment(version=version, project=project, build={}) - python_env = Virtualenv(version=version, build_env=build_env) - builder_class = get_builder_class(project.documentation_type) - builder = builder_class(build_env, python_env) - self.assertEqual(builder.sphinx_builder, 'readthedocs') - def test_build_pdf_latex_failures(self): '''Build failure if latex fails'''