From 771dc336811abf50ed4880dabfce5aefd883a764 Mon Sep 17 00:00:00 2001 From: gzbender Date: Fri, 6 Jul 2018 15:44:19 +0500 Subject: [PATCH 1/7] =?UTF-8?q?LIL-559=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20=D0=B1=D0=BB=D0=BE=D0=BA=20=D0=BA=D0=BE?= =?UTF-8?q?=D0=BC=D0=BC=D0=B5=D0=BD=D1=82=D0=B0=D1=80=D0=B8=D0=B5=D0=B2=20?= =?UTF-8?q?=D0=B2=20=D1=83=D1=80=D0=BE=D0=BA=D0=B8=20=D0=BE=D0=BD=D0=BB?= =?UTF-8?q?=D0=B0=D0=B9=D0=BD-=D1=88=D0=BA=D0=BE=D0=BB=D1=8B=20=D0=92?= =?UTF-8?q?=D1=80=D0=B5=D0=BC=D0=B5=D0=BD=D0=BD=D1=8B=D0=B9=20=D0=BA=D0=BE?= =?UTF-8?q?=D0=BC=D0=BC=D0=B8=D1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/course/templates/course/lesson.html | 10 ++++ web/src/components/Comment.vue | 44 ++++++++++++++++++ web/src/components/Comments.vue | 38 +++++++++++++++ web/src/js/modules/comments.js | 1 + web/src/js/modules/comments_vue.js | 59 ++++++++++++++++++++++++ web/webpack.config.js | 4 ++ 6 files changed, 156 insertions(+) create mode 100644 web/src/components/Comment.vue create mode 100644 web/src/components/Comments.vue create mode 100644 web/src/js/modules/comments_vue.js diff --git a/apps/course/templates/course/lesson.html b/apps/course/templates/course/lesson.html index 662a4dd5..9fbe5a88 100644 --- a/apps/course/templates/course/lesson.html +++ b/apps/course/templates/course/lesson.html @@ -92,6 +92,14 @@ {% endcomment %} +
+
+
Задавайте вопросы:
+
+ +
+
+
Задавайте вопросы:
@@ -129,4 +137,6 @@ {% include 'templates/blocks/share.html' %}
+ {% endblock content %} diff --git a/web/src/components/Comment.vue b/web/src/components/Comment.vue new file mode 100644 index 00000000..b688c6b7 --- /dev/null +++ b/web/src/components/Comment.vue @@ -0,0 +1,44 @@ + + + + diff --git a/web/src/components/Comments.vue b/web/src/components/Comments.vue new file mode 100644 index 00000000..c89a3924 --- /dev/null +++ b/web/src/components/Comments.vue @@ -0,0 +1,38 @@ + + + diff --git a/web/src/js/modules/comments.js b/web/src/js/modules/comments.js index 30b0a815..084b172f 100644 --- a/web/src/js/modules/comments.js +++ b/web/src/js/modules/comments.js @@ -62,3 +62,4 @@ $(document).ready(function () { form.find('.questions__reply-info').hide(); } }); + diff --git a/web/src/js/modules/comments_vue.js b/web/src/js/modules/comments_vue.js new file mode 100644 index 00000000..f511dac5 --- /dev/null +++ b/web/src/js/modules/comments_vue.js @@ -0,0 +1,59 @@ +import Vue from 'vue'; +import Comments from '../../components/Comments'; +//import $ from 'jquery'; + +if (process.env.NODE_ENV === 'development') { + // Enable vue-devtools + Vue.config.devtools = true; +} + +let app = new Vue({ + el: '#comments_block', + data(){ + return { + userId: 123, + accessToken: 123, + comments: [{ + author: { + get_full_name: 'John Doe', + photo: {url: ''}, + }, + created_at_humanize: '12 07 18', + content: 'content content content content', + id: 1, + is_child_node: false + }, { + author: { + get_full_name: 'Sarah Conor', + photo: {url: ''}, + }, + created_at_humanize: '5 05 18', + content: 'hasta la vista', + id: 2, + is_child_node: false, + children: [{ + author: { + get_full_name: 'John Doe', + photo: {url: ''}, + }, + created_at_humanize: '12 07 18', + content: 'content content content content', + id: 10, + is_child_node: true + }, { + author: { + get_full_name: 'Sarah Conor', + photo: {url: ''}, + }, + created_at_humanize: '5 05 18', + content: 'hasta la vista', + id: 20, + is_child_node: true, + }] + }] + } + }, + components: { + 'comments': Comments, + } +}); diff --git a/web/webpack.config.js b/web/webpack.config.js index 3c6785ab..3d47d057 100644 --- a/web/webpack.config.js +++ b/web/webpack.config.js @@ -9,6 +9,7 @@ module.exports = { entry: { app: "./src/js/app.js", courseRedactor: "./src/js/course-redactor.js", + comments_vue: "./src/js/modules/comments_vue.js", mixpanel: "./src/js/third_party/mixpanel-2-latest.js", sprite: glob('./src/icons/*.svg'), images: glob('./src/img/*'), @@ -116,6 +117,9 @@ module.exports = { }, watch: NODE_ENV === 'development', + watchOptions: { + poll: true, + }, devtool: NODE_ENV === 'development' ? 'source-map' : false }; From f9b72b81e7a46d03b75503f1c64e345365f09646 Mon Sep 17 00:00:00 2001 From: gzbender Date: Tue, 10 Jul 2018 14:29:05 +0500 Subject: [PATCH 2/7] =?UTF-8?q?LIL-559,=20API=20=D1=81=D0=BE=D0=B7=D0=B4?= =?UTF-8?q?=D0=B0=D0=BD=D0=B8=D1=8F-=D0=BF=D0=BE=D0=BB=D1=83=D1=87=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D1=8F=20=D0=BA=D0=BE=D0=BC=D0=BC=D0=B5=D0=BD=D1=82?= =?UTF-8?q?=D0=BE=D0=B2,=20=D0=BA=D0=BE=D0=BC=D0=BF=D0=BE=D0=BD=D0=B5?= =?UTF-8?q?=D0=BD=D1=82=D1=8B=20=D0=BA=D0=BE=D0=BC=D0=BC=D0=B5=D0=BD=D1=82?= =?UTF-8?q?=D0=B0=D1=80=D0=B8=D0=B5=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/v1/serializers/course.py | 46 ++++++++++++++ api/v1/urls.py | 3 +- api/v1/views.py | 37 ++++++++++- apps/course/templates/course/lesson.html | 9 ++- web/src/components/Comment.vue | 32 +++++----- web/src/components/Comments.vue | 79 +++++++++++++++++++++--- web/src/js/app.js | 16 +++++ web/src/js/modules/api.js | 21 +++++++ 8 files changed, 211 insertions(+), 32 deletions(-) diff --git a/api/v1/serializers/course.py b/api/v1/serializers/course.py index bdb1a289..298528bc 100644 --- a/api/v1/serializers/course.py +++ b/api/v1/serializers/course.py @@ -300,6 +300,7 @@ class CommentSerializer(serializers.ModelSerializer): 'parent', 'deactivated_at', 'created_at', + 'created_at_humanize', 'update_at', ) @@ -347,3 +348,48 @@ class LessonCommentSerializer(serializers.ModelSerializer): read_only_fields = CommentSerializer.Meta.read_only_fields + ( 'children', ) + + +class CommentCreateSerializer(serializers.ModelSerializer): + OBJ_TYPE_COURSE = 'course' + OBJ_TYPE_LESSON = 'lesson' + + obj_type = serializers.CharField(required=True) + obj_id = serializers.IntegerField(required=True) + + class Meta: + model = Comment + fields = ( + 'id', + 'content', + 'author', + 'parent', + 'deactivated_at', + 'created_at', + 'update_at', + 'obj_type', + 'obj_id', + ) + + read_only_fields = ( + 'id', + 'deactivated_at', + 'created_at', + 'update_at', + ) + + def create(self, validated_data): + obj_type = validated_data.pop('obj_type', None) + obj_id = validated_data.pop('obj_id', None) + if obj_type == self.OBJ_TYPE_COURSE: + validated_data['course_id'] = obj_id + return CourseCommentSerializer().create(validated_data) + elif obj_type == self.OBJ_TYPE_LESSON: + validated_data['lesson_id'] = obj_id + return LessonCommentSerializer().create(validated_data) + + def to_representation(self, instance): + if isinstance(instance, CourseComment): + return CourseCommentSerializer(instance, context=self.context).to_representation(instance) + elif isinstance(instance, LessonComment): + return LessonCommentSerializer(instance, context=self.context).to_representation(instance) diff --git a/api/v1/urls.py b/api/v1/urls.py index 409ed79f..5905dc8b 100644 --- a/api/v1/urls.py +++ b/api/v1/urls.py @@ -17,7 +17,7 @@ from .views import ( GalleryViewSet, GalleryImageViewSet, UserViewSet, LessonViewSet, ImageObjectViewSet, SchoolScheduleViewSet, LiveLessonViewSet, - PaymentViewSet, + PaymentViewSet, ObjectCommentsViewSet, ) router = DefaultRouter() @@ -27,6 +27,7 @@ router.register(r'baners', BanerViewSet, base_name='baners') router.register(r'categories', CategoryViewSet, base_name='categories') router.register(r'courses', CourseViewSet, base_name='courses') router.register(r'comments', CommentViewSet, base_name='comments') +router.register(r'obj-comments', ObjectCommentsViewSet, base_name='obj-comments') router.register(r'materials', MaterialViewSet, base_name='materials') router.register(r'lessons', LessonViewSet, base_name='lessons') router.register(r'likes', LikeViewSet, base_name='likes') diff --git a/api/v1/views.py b/api/v1/views.py index 41cd881a..fb79a335 100644 --- a/api/v1/views.py +++ b/api/v1/views.py @@ -11,9 +11,10 @@ from .serializers.course import ( CategorySerializer, LikeSerializer, CourseSerializer, CourseCreateSerializer, CourseBulkChangeCategorySerializer, - CommentSerializer, + CommentSerializer, CommentCreateSerializer, MaterialSerializer, MaterialCreateSerializer, LessonSerializer, LessonCreateSerializer, + CourseCommentSerializer, LessonCommentSerializer, ) from .serializers.content import ( BanerSerializer, @@ -395,7 +396,7 @@ class ConfigViewSet(generics.RetrieveUpdateAPIView): class CommentViewSet(ExtendedModelViewSet): queryset = Comment.objects.filter(level=0) - serializer_class = CommentSerializer + serializer_class = CommentCreateSerializer permission_classes = (IsAdmin,) def get_queryset(self): @@ -411,6 +412,38 @@ class CommentViewSet(ExtendedModelViewSet): return queryset +class ObjectCommentsViewSet(viewsets.ReadOnlyModelViewSet): + queryset = Comment.objects.filter(level=0) + OBJ_TYPE_COURSE = 'course' + OBJ_TYPE_LESSON = 'lesson' + permission_classes = (IsAdmin,) + + def get_queryset(self): + queryset = self.queryset + obj_type = self.request.query_params.get('obj_type') + obj_id = self.request.query_params.get('obj_id') + is_deactivated = self.request.query_params.get('is_deactivated', '0') + if obj_type == self.OBJ_TYPE_COURSE: + queryset = CourseComment.objects.filter(course=obj_id) + elif obj_type == self.OBJ_TYPE_LESSON: + queryset = LessonComment.objects.filter(lesson=obj_id) + if is_deactivated == '0': + queryset = queryset + elif is_deactivated == '1': + queryset = queryset.filter(deactivated_at__isnull=True) + elif is_deactivated == '2': + queryset = queryset.filter(deactivated_at__isnull=False) + return queryset + + def get_serializer_class(self): + obj_type = self.request.query_params.get('obj_type') + if obj_type == self.OBJ_TYPE_COURSE: + serializer_class = CourseCommentSerializer + elif obj_type == self.OBJ_TYPE_LESSON: + serializer_class = LessonCommentSerializer + return serializer_class + + class AuthorRequestViewSet(ExtendedModelViewSet): queryset = AuthorRequest.objects.all() serializer_class = AuthorRequestSerializer diff --git a/apps/course/templates/course/lesson.html b/apps/course/templates/course/lesson.html index 9fbe5a88..18e51e78 100644 --- a/apps/course/templates/course/lesson.html +++ b/apps/course/templates/course/lesson.html @@ -96,7 +96,12 @@
Задавайте вопросы:
- +
@@ -137,6 +142,4 @@ {% include 'templates/blocks/share.html' %} - {% endblock content %} diff --git a/web/src/components/Comment.vue b/web/src/components/Comment.vue index b688c6b7..1abdd00b 100644 --- a/web/src/components/Comment.vue +++ b/web/src/components/Comment.vue @@ -1,26 +1,26 @@ @@ -15,19 +31,62 @@ export default { name: 'comments', - props: ['objType', 'objId', 'nodes', 'userId', 'accessToken'], - methods: { - reply() { - // + props: ['objType', 'objId', 'comments', 'userId', 'userPhoto', 'accessToken', 'defaultAuthorPicture'], + data() { + return { + loading: false, + replyTo: null, + content: '', + nodes: [], + } + }, + computed: { + replyAnchor(){ + return this.replyTo ? `#question__${this.replyTo.id}` : ''; } }, + methods: { + clear() { + this.content = '', + this.replyTo = null + }, + cancelReply() { + this.replyTo = null; + }, + post() { + this.loading = true; + let request = api.addComment(this.objId, this.objType, { + content: this.content, + author: this.userId, + parent: this.replyTo && this.replyTo.id, + }, this.accessToken); + request.then((response) => { + this.loading = false; + if(this.replyTo){ + this.replyTo.children.push(response.data); + } + else { + this.nodes.push(response.data); + } + this.clear(); + }).catch(() => { + this.loading = false; + }); + }, + onReply(replyTo) { + this.replyTo = replyTo; + }, + }, mounted() { - if(! this.nodes && this.objType && this.objId){ - request = api.loadComments(this.objId, this.objType, this.accessToken); + if(this.comments && this.comments.length){ + this.nodes = this.comments; + } + else if(this.objType && this.objId){ + let request = api.getObjComments(this.objId, this.objType, this.accessToken); request .then((response) => { - this.nodes = response.data; - }) + this.nodes = response.data.results; + }); } console.log('nodes', this.nodes); }, diff --git a/web/src/js/app.js b/web/src/js/app.js index 16651100..7be8af4e 100644 --- a/web/src/js/app.js +++ b/web/src/js/app.js @@ -11,9 +11,25 @@ import "./modules/tabs"; import "./modules/popup"; import "./modules/courses"; import "./modules/comments"; +import "./modules/comments"; import "./modules/password-show"; import "./modules/profile"; import "./modules/notification"; import "./modules/mixpanel"; import "../sass/app.sass"; + +import Vue from 'vue'; +import Comments from '../components/Comments'; + +if (process.env.NODE_ENV === 'development') { + // Enable vue-devtools + Vue.config.devtools = true; +} + +let app = new Vue({ + el: '.js-outer', + components: { + 'comments': Comments, + } +}) diff --git a/web/src/js/modules/api.js b/web/src/js/modules/api.js index 990ac7b2..003153a3 100644 --- a/web/src/js/modules/api.js +++ b/web/src/js/modules/api.js @@ -502,4 +502,25 @@ export const api = { } }); }, + getObjComments: (objId, objType, accessToken) => { + return api.get('/api/v1/obj-comments/', { + params: { + obj_id: objId, + obj_type: objType, + }, + headers: { + 'Authorization': `Token ${accessToken}`, + } + }); + }, + addComment: (objId, objType, commentJson, accessToken) => { + let data = commentJson; + data.obj_id = objId; + data.obj_type = objType; + return api.post('/api/v1/comments/', data, { + headers: { + 'Authorization': `Token ${accessToken}`, + } + }); + } }; From 3f4426618f1814fd642705646413c45297efcac6 Mon Sep 17 00:00:00 2001 From: gzbender Date: Thu, 12 Jul 2018 02:25:33 +0500 Subject: [PATCH 3/7] =?UTF-8?q?LIL-559=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20=D0=B1=D0=BB=D0=BE=D0=BA=20=D0=BA=D0=BE?= =?UTF-8?q?=D0=BC=D0=BC=D0=B5=D0=BD=D1=82=D0=B0=D1=80=D0=B8=D0=B5=D0=B2=20?= =?UTF-8?q?=D0=B2=20=D1=83=D1=80=D0=BE=D0=BA=D0=B8=20=D0=BE=D0=BD=D0=BB?= =?UTF-8?q?=D0=B0=D0=B9=D0=BD-=D1=88=D0=BA=D0=BE=D0=BB=D1=8B:=20comments?= =?UTF-8?q?=20with=20using=20Pusher?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/v1/views.py | 40 ++++-- apps/course/templates/course/lesson.html | 34 +---- project/pusher.py | 14 ++ project/settings.py | 7 + project/templates/lilcity/index.html | 11 ++ requirements.txt | 2 + web/src/components/Comment.vue | 76 ++++++---- web/src/components/CommentForm.vue | 42 ++++++ web/src/components/Comments.vue | 169 ++++++++++++++--------- web/src/js/modules/api.js | 11 +- web/webpack.config.js | 4 +- 11 files changed, 277 insertions(+), 133 deletions(-) create mode 100644 project/pusher.py create mode 100644 web/src/components/CommentForm.vue diff --git a/api/v1/views.py b/api/v1/views.py index fb79a335..5505310a 100644 --- a/api/v1/views.py +++ b/api/v1/views.py @@ -64,6 +64,7 @@ from apps.payment.models import ( ) from apps.school.models import SchoolSchedule, LiveLesson from apps.user.models import AuthorRequest +from project.pusher import pusher User = get_user_model() @@ -395,15 +396,15 @@ class ConfigViewSet(generics.RetrieveUpdateAPIView): class CommentViewSet(ExtendedModelViewSet): - queryset = Comment.objects.filter(level=0) - serializer_class = CommentCreateSerializer - permission_classes = (IsAdmin,) + queryset = Comment.objects.all() + serializer_class = CommentSerializer + permission_classes = (IsAuthorObjectOrAdmin,) def get_queryset(self): queryset = self.queryset is_deactivated = self.request.query_params.get('is_deactivated', '0') if is_deactivated == '0': - queryset = queryset + queryset = queryset.filter(level=0) elif is_deactivated == '1': queryset = queryset.filter(deactivated_at__isnull=True) elif is_deactivated == '2': @@ -412,11 +413,12 @@ class CommentViewSet(ExtendedModelViewSet): return queryset -class ObjectCommentsViewSet(viewsets.ReadOnlyModelViewSet): - queryset = Comment.objects.filter(level=0) +class ObjectCommentsViewSet(ExtendedModelViewSet): OBJ_TYPE_COURSE = 'course' OBJ_TYPE_LESSON = 'lesson' - permission_classes = (IsAdmin,) + queryset = Comment.objects.all() + serializer_class = CommentCreateSerializer + permission_classes = (IsAuthorObjectOrAdmin,) def get_queryset(self): queryset = self.queryset @@ -424,11 +426,11 @@ class ObjectCommentsViewSet(viewsets.ReadOnlyModelViewSet): obj_id = self.request.query_params.get('obj_id') is_deactivated = self.request.query_params.get('is_deactivated', '0') if obj_type == self.OBJ_TYPE_COURSE: - queryset = CourseComment.objects.filter(course=obj_id) + queryset = CourseComment.objects.filter(course=obj_id, parent__isnull=True) elif obj_type == self.OBJ_TYPE_LESSON: - queryset = LessonComment.objects.filter(lesson=obj_id) + queryset = LessonComment.objects.filter(lesson=obj_id, parent__isnull=True) if is_deactivated == '0': - queryset = queryset + queryset = queryset.filter(level=0) elif is_deactivated == '1': queryset = queryset.filter(deactivated_at__isnull=True) elif is_deactivated == '2': @@ -436,6 +438,8 @@ class ObjectCommentsViewSet(viewsets.ReadOnlyModelViewSet): return queryset def get_serializer_class(self): + if self.request.method == 'POST': + return CommentCreateSerializer obj_type = self.request.query_params.get('obj_type') if obj_type == self.OBJ_TYPE_COURSE: serializer_class = CourseCommentSerializer @@ -443,6 +447,22 @@ class ObjectCommentsViewSet(viewsets.ReadOnlyModelViewSet): serializer_class = LessonCommentSerializer return serializer_class + def perform_create(self, serializer): + obj_type = self.request.data.get('obj_type') + obj_id = self.request.data.get('obj_id') + serializer.save() + pusher().trigger(f'comments_{obj_type}_{obj_id}', 'add', serializer.data) + + def perform_destroy(self, instance): + obj_type = None + if isinstance(instance, LessonComment): + obj_type = self.OBJ_TYPE_LESSON + elif isinstance(instance, CourseComment): + obj_type = self.OBJ_TYPE_COURSE + serializer = self.get_serializer(instance) + pusher().trigger(f'comments_{obj_type}_{obj_id}', 'delete', serializer.data) + instance.delete() + class AuthorRequestViewSet(ExtendedModelViewSet): queryset = AuthorRequest.objects.all() diff --git a/apps/course/templates/course/lesson.html b/apps/course/templates/course/lesson.html index 18e51e78..9e79279d 100644 --- a/apps/course/templates/course/lesson.html +++ b/apps/course/templates/course/lesson.html @@ -96,7 +96,7 @@
Задавайте вопросы:
-
-
-
-
Задавайте вопросы:
-
- {% if request.user.is_authenticated %} -
-
- -
-
-
- -
- -
-
- {% else %} -
Только зарегистрированные пользователи могут оставлять комментарии.
- {% endif %} -
- {% include "templates/blocks/comments.html" with object=lesson %} -
-
-
-
{% include 'templates/blocks/share.html' %} diff --git a/project/pusher.py b/project/pusher.py new file mode 100644 index 00000000..af6c74a8 --- /dev/null +++ b/project/pusher.py @@ -0,0 +1,14 @@ +from django.conf import settings +from pusher import Pusher + + +def pusher(): + try: + pusher_cluster = settings.PUSHER_CLUSTER + except AttributeError: + pusher_cluster = 'mt1' + + return Pusher(app_id=settings.PUSHER_APP_ID, + key=settings.PUSHER_KEY, + secret=settings.PUSHER_SECRET, + cluster=pusher_cluster) diff --git a/project/settings.py b/project/settings.py index 9323745c..80c9e4ce 100644 --- a/project/settings.py +++ b/project/settings.py @@ -194,6 +194,13 @@ TWILIO_FROM_PHONE = os.getenv('TWILIO_FROM_PHONE', '+37128914409') ACTIVE_LINK_STRICT = True +# PUSHER settings + +PUSHER_APP_ID = u"" +PUSHER_KEY = u"" +PUSHER_SECRET = u"" +PUSHER_CLUSTER = u"" + # DRF settings REST_FRAMEWORK = { diff --git a/project/templates/lilcity/index.html b/project/templates/lilcity/index.html index 5d7b9d2d..187cd913 100644 --- a/project/templates/lilcity/index.html +++ b/project/templates/lilcity/index.html @@ -38,6 +38,7 @@ {% endcompress %} + + + diff --git a/web/src/components/CommentForm.vue b/web/src/components/CommentForm.vue new file mode 100644 index 00000000..80041646 --- /dev/null +++ b/web/src/components/CommentForm.vue @@ -0,0 +1,42 @@ + + + + diff --git a/web/src/components/Comments.vue b/web/src/components/Comments.vue index dcbf2a0d..40c7ea60 100644 --- a/web/src/components/Comments.vue +++ b/web/src/components/Comments.vue @@ -1,97 +1,142 @@ + + diff --git a/web/src/js/modules/api.js b/web/src/js/modules/api.js index 003153a3..7aa95c8a 100644 --- a/web/src/js/modules/api.js +++ b/web/src/js/modules/api.js @@ -513,11 +513,18 @@ export const api = { } }); }, - addComment: (objId, objType, commentJson, accessToken) => { + addObjComment: (objId, objType, commentJson, accessToken) => { let data = commentJson; data.obj_id = objId; data.obj_type = objType; - return api.post('/api/v1/comments/', data, { + return api.post('/api/v1/obj-comments/', data, { + headers: { + 'Authorization': `Token ${accessToken}`, + } + }); + }, + removeComment: (commentId, accessToken) => { + return api.delete(`/api/v1/comments/${commentId}/`, { headers: { 'Authorization': `Token ${accessToken}`, } diff --git a/web/webpack.config.js b/web/webpack.config.js index 3d47d057..8cd8b8f4 100644 --- a/web/webpack.config.js +++ b/web/webpack.config.js @@ -9,7 +9,6 @@ module.exports = { entry: { app: "./src/js/app.js", courseRedactor: "./src/js/course-redactor.js", - comments_vue: "./src/js/modules/comments_vue.js", mixpanel: "./src/js/third_party/mixpanel-2-latest.js", sprite: glob('./src/icons/*.svg'), images: glob('./src/img/*'), @@ -118,7 +117,8 @@ module.exports = { watch: NODE_ENV === 'development', watchOptions: { - poll: true, + ignored: "/node_modules/", + poll: 2000, }, devtool: NODE_ENV === 'development' ? 'source-map' : false From 470d7252eba9231664003e9a50fce7ae91a73479 Mon Sep 17 00:00:00 2001 From: gzbender Date: Thu, 12 Jul 2018 19:10:06 +0500 Subject: [PATCH 4/7] =?UTF-8?q?LIL-559=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20=D0=B1=D0=BB=D0=BE=D0=BA=20=D0=BA=D0=BE?= =?UTF-8?q?=D0=BC=D0=BC=D0=B5=D0=BD=D1=82=D0=B0=D1=80=D0=B8=D0=B5=D0=B2=20?= =?UTF-8?q?=D0=B2=20=D1=83=D1=80=D0=BE=D0=BA=D0=B8=20=D0=BE=D0=BD=D0=BB?= =?UTF-8?q?=D0=B0=D0=B9=D0=BD-=D1=88=D0=BA=D0=BE=D0=BB=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/v1/views.py | 27 ++++++++++++++----- web/src/components/Comment.vue | 13 ++++----- web/src/components/CommentForm.vue | 10 +++---- web/src/components/Comments.vue | 20 +++++--------- web/src/js/modules/api.js | 4 +-- web/src/sass/_common.sass | 42 +++++++++++++++++++++++++++--- 6 files changed, 78 insertions(+), 38 deletions(-) diff --git a/api/v1/views.py b/api/v1/views.py index 5505310a..bc184a6d 100644 --- a/api/v1/views.py +++ b/api/v1/views.py @@ -424,23 +424,24 @@ class ObjectCommentsViewSet(ExtendedModelViewSet): queryset = self.queryset obj_type = self.request.query_params.get('obj_type') obj_id = self.request.query_params.get('obj_id') - is_deactivated = self.request.query_params.get('is_deactivated', '0') + is_deactivated = self.request.query_params.get('is_deactivated') if obj_type == self.OBJ_TYPE_COURSE: - queryset = CourseComment.objects.filter(course=obj_id, parent__isnull=True) + queryset = CourseComment.objects.filter(course=obj_id) elif obj_type == self.OBJ_TYPE_LESSON: - queryset = LessonComment.objects.filter(lesson=obj_id, parent__isnull=True) + queryset = LessonComment.objects.filter(lesson=obj_id) if is_deactivated == '0': queryset = queryset.filter(level=0) elif is_deactivated == '1': queryset = queryset.filter(deactivated_at__isnull=True) elif is_deactivated == '2': queryset = queryset.filter(deactivated_at__isnull=False) - return queryset + return queryset.order_by('update_at') def get_serializer_class(self): if self.request.method == 'POST': return CommentCreateSerializer obj_type = self.request.query_params.get('obj_type') + serializer_class = CommentSerializer if obj_type == self.OBJ_TYPE_COURSE: serializer_class = CourseCommentSerializer elif obj_type == self.OBJ_TYPE_LESSON: @@ -451,18 +452,32 @@ class ObjectCommentsViewSet(ExtendedModelViewSet): obj_type = self.request.data.get('obj_type') obj_id = self.request.data.get('obj_id') serializer.save() - pusher().trigger(f'comments_{obj_type}_{obj_id}', 'add', serializer.data) + try: + pusher().trigger(f'comments_{obj_type}_{obj_id}', 'add', serializer.data) + except Exception as e: + print(e) def perform_destroy(self, instance): obj_type = None + obj_id = None if isinstance(instance, LessonComment): obj_type = self.OBJ_TYPE_LESSON + obj_id = instance.lesson_id elif isinstance(instance, CourseComment): obj_type = self.OBJ_TYPE_COURSE + obj_id = instance.course_id serializer = self.get_serializer(instance) - pusher().trigger(f'comments_{obj_type}_{obj_id}', 'delete', serializer.data) + try: + pusher().trigger(f'comments_{obj_type}_{obj_id}', 'delete', serializer.data) + except Exception as e: + print(e) instance.delete() + def list(self, request, *args, **kwargs): + queryset = self.filter_queryset(self.get_queryset()).filter(parent__isnull=True) + serializer = self.get_serializer(queryset, many=True) + return Response(serializer.data) + class AuthorRequestViewSet(ExtendedModelViewSet): queryset = AuthorRequest.objects.all() diff --git a/web/src/components/Comment.vue b/web/src/components/Comment.vue index e5f262d7..279992f9 100644 --- a/web/src/components/Comment.vue +++ b/web/src/components/Comment.vue @@ -1,6 +1,6 @@