From e10b76ee2011f6b2238564d963e8af49d7aa55aa Mon Sep 17 00:00:00 2001 From: gzbender Date: Wed, 9 Jan 2019 02:29:16 +0300 Subject: [PATCH 01/12] =?UTF-8?q?LIL-731=20=D0=A3=D0=BF=D1=80=D0=BE=D1=81?= =?UTF-8?q?=D1=82=D0=B8=D1=82=D1=8C=20=D0=BF=D0=BE=D0=B4=D0=BA=D0=BB=D1=8E?= =?UTF-8?q?=D1=87=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BA=D0=BE=D0=BC=D0=BF=D0=BE?= =?UTF-8?q?=D0=BD=D0=B5=D0=BD=D1=82=D0=BE=D0=B2=20=D0=B8=20JS=20=D1=81?= =?UTF-8?q?=D0=BA=D1=80=D0=B8=D0=BF=D1=82=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../templates/content/contest_edit.html | 1 - apps/course/templates/course/course_edit.html | 8 +- project/templates/blocks/lil_store_js.html | 12 +- web/package.json | 1 + web/src/js/app.js | 33 ++-- .../contest-edit.js} | 3 +- web/src/js/pages/contest.js | 5 + .../course-edit.js} | 4 +- web/src/js/{modules => pages}/profile.js | 6 +- web/src/js/{ => pages}/user-gallery-edit.js | 5 +- web/src/sass/app.sass | 2 +- web/src/sass/components/contest-work.scss | 0 web/src/sass/pages/course-edit.scss | 166 ++++++++++++++++++ web/webpack.config.js | 67 ++++++- 14 files changed, 274 insertions(+), 39 deletions(-) rename web/src/js/{contest-redactor.js => pages/contest-edit.js} (50%) create mode 100644 web/src/js/pages/contest.js rename web/src/js/{course-redactor.js => pages/course-edit.js} (85%) rename web/src/js/{modules => pages}/profile.js (94%) rename web/src/js/{ => pages}/user-gallery-edit.js (77%) create mode 100644 web/src/sass/components/contest-work.scss create mode 100644 web/src/sass/pages/course-edit.scss diff --git a/apps/content/templates/content/contest_edit.html b/apps/content/templates/content/contest_edit.html index d1c26b62..409405a6 100644 --- a/apps/content/templates/content/contest_edit.html +++ b/apps/content/templates/content/contest_edit.html @@ -13,6 +13,5 @@ {% endblock content %} {% block foot %} - {% endblock foot %} diff --git a/apps/course/templates/course/course_edit.html b/apps/course/templates/course/course_edit.html index ee3143dd..296f8da1 100644 --- a/apps/course/templates/course/course_edit.html +++ b/apps/course/templates/course/course_edit.html @@ -13,7 +13,7 @@ access-token="{{ request.user.auth_token }}" {% if object and object.id %}:course-id="{{ object.id }}"{% endif %}> {% endblock content %} -{% block foot %} - - -{% endblock foot %} +{% block pre_app_js %} + + +{% endblock pre_app_js %} diff --git a/project/templates/blocks/lil_store_js.html b/project/templates/blocks/lil_store_js.html index 39770603..7556240c 100644 --- a/project/templates/blocks/lil_store_js.html +++ b/project/templates/blocks/lil_store_js.html @@ -21,10 +21,14 @@ components: {}, urls: { courses: "{% url 'courses' %}", + courseEdit: /\/course\/\d+\/edit/, + courseCreate: "{% url 'course_create' %}", userProfileEdit: "{% url 'user-edit-profile' %}", userProfile: "{% url 'user-profile' %}", userBonuses: "{% url 'user-bonuses' %}", faq: "{% url 'faq' %}", + contestEdit: /contest\/\w+\/edit/, + userGalleryEdit: "{% url 'user-gallery-edit' %}", }, flags: { referrer: '{{ referrer.id|default:'' }}', @@ -33,8 +37,12 @@ isGiftCertificateUrl: {{ is_gift_certificate_url|yesno:"true,false" }}, }, data: {}, - urlIs: (urlPatternName) => { - return window.location.pathname.search(window.LIL_STORE.urls[urlPatternName]) > -1; + urlIs: (urlPatternNames) => { + if(! Array.isArray(urlPatternNames)){ + urlPatternNames = [urlPatternNames]; + } + return urlPatternNames.filter( + urlPatternName => window.location.pathname.search(window.LIL_STORE.urls[urlPatternName]) > -1).length > 0; }, isIndexPage: window.location.pathname == '/', }; diff --git a/web/package.json b/web/package.json index f2c6d260..1c128202 100755 --- a/web/package.json +++ b/web/package.json @@ -41,6 +41,7 @@ "baguettebox.js": "^1.10.0", "clipboard": "^2.0.1", "downscale": "^1.0.4", + "extract-loader": "^3.1.0", "glob": "^7.1.2", "history": "^4.7.2", "ilyabirman-likely": "^2.3.0", diff --git a/web/src/js/app.js b/web/src/js/app.js index 1588467f..313141c1 100644 --- a/web/src/js/app.js +++ b/web/src/js/app.js @@ -13,7 +13,6 @@ import "./modules/tabs"; import "./modules/popup"; import "./modules/courses"; import "./modules/comments"; -import "./modules/comments"; import "./modules/password-show"; import "./modules/notification"; import "./modules/mixpanel"; @@ -25,9 +24,8 @@ import Vue from 'vue'; import Vuelidate from 'vuelidate'; import VueAutosize from '../components/directives/autosize' import Comments from '../components/Comments'; -import UploadContestWork from '../components/UploadContestWork.vue'; -import ContestWorks from '../components/ContestWorks.vue'; import Likes from '../components/blocks/Likes.vue'; +import FAQ from '../components/FAQ.vue'; Vue.use(Vuelidate); Vue.use(VueAutosize); @@ -38,23 +36,30 @@ if (process.env.NODE_ENV === 'development') { } const components = { - UploadContestWork, - ContestWorks, Likes, Comments, + FAQ, }; +// +//if(window.LIL_STORE.urlIs('userProfileEdit') || window.LIL_STORE.urlIs('userBonuses')){ +// const profile = require("./modules/profile"); +// profile.main(); +//} +//if(window.LIL_STORE.urlIs(['courseEdit', 'courseCreate'])){ +// const courseEdit = require("./modules/course-redactor"); +// courseEdit.main(); +//} +//if(window.LIL_STORE.urlIs('contestEdit')){ +// const ContestRedactor = require('../components/ContestRedactor.vue'); +// components['contest-redactor'] = ContestRedactor.default; +//} +//if(window.LIL_STORE.urlIs('userGalleryEdit')){ +// const userGalleryEdit = require("./modules/user-gallery-edit"); +// userGalleryEdit.main(); +//} Object.assign(components, window.LIL_STORE.components); -if(window.LIL_STORE.urlIs('faq')){ - const FAQ = require('../components/FAQ.vue'); - components['faq'] = FAQ.default; -} -if(window.LIL_STORE.urlIs('userProfileEdit') || window.LIL_STORE.urlIs('userBonuses')){ - const profile = require("./modules/profile"); - profile.main(); -} - const app = new Vue({ el: '#lilcity-vue-app', data() { diff --git a/web/src/js/contest-redactor.js b/web/src/js/pages/contest-edit.js similarity index 50% rename from web/src/js/contest-redactor.js rename to web/src/js/pages/contest-edit.js index afbbb193..e1daf8ef 100644 --- a/web/src/js/contest-redactor.js +++ b/web/src/js/pages/contest-edit.js @@ -1,4 +1,3 @@ -import ContestRedactor from '../components/ContestRedactor.vue' +import ContestRedactor from '../../components/ContestRedactor.vue'; window.LIL_STORE.components['contest-redactor'] = ContestRedactor; - diff --git a/web/src/js/pages/contest.js b/web/src/js/pages/contest.js new file mode 100644 index 00000000..d5785c15 --- /dev/null +++ b/web/src/js/pages/contest.js @@ -0,0 +1,5 @@ +import UploadContestWork from '../../components/UploadContestWork.vue'; +import ContestWorks from '../../components/ContestWorks.vue'; + +window.LIL_STORE.components['upload-contest-work'] = UploadContestWork; +window.LIL_STORE.components['contest-works'] = ContestWorks; diff --git a/web/src/js/course-redactor.js b/web/src/js/pages/course-edit.js similarity index 85% rename from web/src/js/course-redactor.js rename to web/src/js/pages/course-edit.js index 45b3c970..e7a2fcc4 100644 --- a/web/src/js/course-redactor.js +++ b/web/src/js/pages/course-edit.js @@ -1,5 +1,5 @@ -import 'babel-polyfill' -import CourseRedactor from '../components/CourseRedactor.vue' +import 'babel-polyfill'; +import CourseRedactor from '../../components/CourseRedactor.vue'; import $ from 'jquery'; window.LIL_STORE.components['course-redactor'] = CourseRedactor; diff --git a/web/src/js/modules/profile.js b/web/src/js/pages/profile.js similarity index 94% rename from web/src/js/modules/profile.js rename to web/src/js/pages/profile.js index 11f60b76..9ac8120a 100644 --- a/web/src/js/modules/profile.js +++ b/web/src/js/pages/profile.js @@ -1,9 +1,9 @@ import $ from 'jquery'; import slugify from 'slugify'; import ClipboardJS from 'clipboard'; -import {showNotification} from './notification'; +import {showNotification} from '../modules/notification'; -export const main = () => { +$(document).ready(function () { if(window.LIL_STORE.urlIs('userBonuses')){ $('#referrer-url').select().click(function(){ $(this).select(); @@ -53,4 +53,4 @@ export const main = () => { }); changeSlug(); } -} +}); diff --git a/web/src/js/user-gallery-edit.js b/web/src/js/pages/user-gallery-edit.js similarity index 77% rename from web/src/js/user-gallery-edit.js rename to web/src/js/pages/user-gallery-edit.js index 8c957d11..c7ce4449 100644 --- a/web/src/js/user-gallery-edit.js +++ b/web/src/js/pages/user-gallery-edit.js @@ -1,6 +1,7 @@ -import BlockImages from '../components/blocks/BlockImages.vue'; +import BlockImages from '../../components/blocks/BlockImages.vue'; import $ from 'jquery'; -import {api} from "./modules/api"; +import {api} from "../modules/api"; + window.LIL_STORE.components['block-images'] = BlockImages; diff --git a/web/src/sass/app.sass b/web/src/sass/app.sass index 82cdc94a..38c37335 100755 --- a/web/src/sass/app.sass +++ b/web/src/sass/app.sass @@ -2,4 +2,4 @@ @import helpers/all @import generated/sprite-svg @import common -@import '~baguettebox.js/dist/baguetteBox.min.css'; \ No newline at end of file +@import '~baguettebox.js/dist/baguetteBox.min.css'; diff --git a/web/src/sass/components/contest-work.scss b/web/src/sass/components/contest-work.scss new file mode 100644 index 00000000..e69de29b diff --git a/web/src/sass/pages/course-edit.scss b/web/src/sass/pages/course-edit.scss new file mode 100644 index 00000000..ad1d219e --- /dev/null +++ b/web/src/sass/pages/course-edit.scss @@ -0,0 +1,166 @@ +.vdp-datepicker__calendar { + width: 240px; + margin-top: 10px; + padding: 5px; + background: white; + box-shadow: 0 2px 20px 0 rgba(0, 0, 0, 0.1); + z-index: 99 !important; + + header { + display: flex; + margin-bottom: 5px; + -ms-flex-align: center; + align-items: center; + } + + .prev, .next { + font-size: 0; + cursor: pointer; + order: 1; + width: auto !important; + padding: 10px; + } + + .prev { + order: 1; + } + + .next { + order: 3; + } + + .prev:before, .next:before { + content: ''; + display: block; + width: 10px; + height: 10px; + border: solid #E6E6E6; + border-width: 2px 2px 0 0; + } + + .prev:after, .next:after { + content: none !important; + } + + .prev:before { + transform: rotate(-135deg); + } + + .next:before { + transform: rotate(45deg); + } +} + +.kit__preview { + img { + width: 140px; + height: 140px; + } +} + +.kit__photo { + width: 140px; + height: 140px; +} + +.kit__section-remove { + button.sortable__handle { + margin-right: 10px; + cursor: -webkit-grab; + cursor: grab; + + svg.icon-hamburger { + width: 1em; + height: 1em; + } + } +} + +.sortable-ghost, .sortable-chosen { + background: white; + border-radius: 10px; +} + +.course-redactor__preview-button-bg-save { + background-color: #58fffb; +} +.course-redactor__preview-button { + transition: backgroundColor 0.5s ease-in-out; +} + +.field_text { + height: 270px; + overflow: scroll; +} + +.courses__item { + flex: 0 0 300px; +} + +.courses__item .field { + margin-bottom: 0; +} + +.courses__content .redactor-box { + overflow-x: visible; + overflow-y: auto; + max-height: 200px; + background: none; + margin-top: 10px; +} + +.courses__content .redactor-layer{ + background: none; +} + +.courses__theme { + flex: 1; +} + +.courses__price { + margin-left: 20px; +} + +.courses__preview { + .upload { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + } + + .upload__title { + color: #888888; + font-size: 16px; + margin-top: 100px; + width: 100%; + text-align: center; + } + + .upload__file { + width: 100%; + height: 100%; + } +} + +.course-delete-cover { + left: 5px; + position: absolute; + bottom: 3px; +} + +.field-category .select__head { + font-size: inherit; + line-height: inherit; + height: auto; +} + +.datetime-fields { + display: flex; +} + +.field-time { + margin-left: 10px; + flex: 50%; +} diff --git a/web/webpack.config.js b/web/webpack.config.js index c2182909..886156ed 100644 --- a/web/webpack.config.js +++ b/web/webpack.config.js @@ -5,33 +5,36 @@ const NODE_ENV = process.env.NODE_ENV || 'development'; const ExtractTextPlugin = require("extract-text-webpack-plugin"); const SpriteLoaderPlugin = require('svg-sprite-loader/plugin'); + module.exports = { entry: { app: "./src/js/app.js", - courseRedactor: "./src/js/course-redactor.js", - contestRedactor: "./src/js/contest-redactor.js", - userGalleryEdit: "./src/js/user-gallery-edit.js", + courseEdit: "./src/js/pages/course-edit.js", + contest: "./src/js/pages/contest.js", + contestEdit: "./src/js/pages/contest-edit.js", + profile: "./src/js/pages/profile.js", + userGalleryEdit: "./src/js/pages/user-gallery-edit.js", mixpanel: "./src/js/third_party/mixpanel-2-latest.js", sprite: glob('./src/icons/*.svg'), images: glob('./src/img/*.*'), imagesCertificates: glob('./src/img/user-certificates/*'), imagesGiftCertificates: glob('./src/img/gift-certificates/*'), imagesReviews: glob('./src/img/reviews/*'), - fonts: glob('./src/fonts/*') + fonts: glob('./src/fonts/*'), +// pages: glob('./src/js/pages/*'), +// pagesCss: glob('./src/sass/pages/*'), }, output: { path: path.join(__dirname, "build"), filename: NODE_ENV === 'development' ? '[name].js' : '[name].js', library: '[name]', - //filename: NODE_ENV === 'development' ? '[name].js' : '[name].[id].[chunkhash].js', - //library: '[name]', publicPath: '/static/', }, module: { loaders: [ { test: /\.js$/, - exclude: /(node_modules|bower_components|third_party)/, + exclude: /(node_modules|bower_components|third_party|pages)/, use: { loader: 'babel-loader', options: { @@ -41,7 +44,7 @@ module.exports = { }, { test: /third_party\/.*\.js$/, - exclude: /(node_modules|bower_components)/, + exclude: /(node_modules|bower_components|pages)/, use: { loader: 'file-loader', options: { @@ -49,6 +52,22 @@ module.exports = { } } }, +// { +// test: /\.js$/, +// include: [path.resolve(__dirname, 'src/js/pages')], +// use: [{ +// loader: 'file-loader', +// options: { +// name: "[name].[ext]" +// } +// }, +// { +// loader: 'babel-loader', +// options: { +// "presets": ["es2015"], +// } +// }] +// }, { test: /\.css$/, use: ExtractTextPlugin.extract({ @@ -58,11 +77,39 @@ module.exports = { }, { test: /\.s[ac]ss$/, + exclude: [path.resolve(__dirname, 'src/sass/pages')], use: ExtractTextPlugin.extract({ fallback: 'style-loader', use: ['css-loader', 'sass-loader'] }) }, + /* { + test: /\.s[ac]ss$/, + include: [path.resolve(__dirname, 'src/sass/pages')], + use: [ + { + loader: 'file-loader', + options: { + name: '[name].css', + } + }, + { + loader: 'extract-loader', + }, + { + loader: 'css-loader', + options: { + sourceMap: true + } + }, + { + loader: 'sass-loader', + options: { + sourceMap: true + } + } + ] + }, */ { test: /\.vue$/, loader: 'vue-loader', @@ -127,6 +174,10 @@ module.exports = { "window.$": "jquery" }), new ExtractTextPlugin('[name].css'), +// new MiniCssExtractPlugin({ +// filename: "[name].css", +// chunkFilename: "[id].css" +// }), ], resolve: { From 2165c4fc0fea71e089ca0d4b6569feb61244d67b Mon Sep 17 00:00:00 2001 From: gzbender Date: Tue, 15 Jan 2019 17:47:41 +0300 Subject: [PATCH 02/12] LIL-712 --- apps/course/models.py | 2 +- apps/course/views.py | 26 ++++++++++++++++++++++++++ web/src/components/CourseRedactor.vue | 2 +- web/src/js/modules/api.js | 2 +- 4 files changed, 29 insertions(+), 3 deletions(-) diff --git a/apps/course/models.py b/apps/course/models.py index 42a1dd81..23b5acfa 100644 --- a/apps/course/models.py +++ b/apps/course/models.py @@ -136,7 +136,7 @@ class Course(BaseModel, DeactivatedMixin): return self.get_absolute_url() def get_absolute_url(self): - return reverse_lazy('course', args=[self.slug or self.id]) + return reverse_lazy('course', args=[self.slug.lower() if self.slug else self.id]) @property def is_free(self): diff --git a/apps/course/views.py b/apps/course/views.py index 07ca6bad..5e625c42 100644 --- a/apps/course/views.py +++ b/apps/course/views.py @@ -200,6 +200,32 @@ class CourseView(DetailView): # ((self.object.status != Course.PUBLISHED and request.user.role != User.ADMIN_ROLE) or # (self.object.status != Course.PUBLISHED and request.user.role != User.AUTHOR_ROLE and self.object.author != request.user)): + def get_object(self, queryset=None): + if queryset is None: + queryset = self.get_queryset() + + pk = self.kwargs.get(self.pk_url_kwarg) + slug = self.kwargs.get(self.slug_url_kwarg) + if pk is not None: + queryset = queryset.filter(pk=pk) + + if slug is not None and (pk is None or self.query_pk_and_slug): + slug_field = self.get_slug_field() + queryset = queryset.filter(**{'%s__iexact' % slug_field: slug}) + + if pk is None and slug is None: + raise AttributeError("Generic detail view %s must be called with " + "either an object pk or a slug." + % self.__class__.__name__) + + try: + # Get the single item from the filtered queryset + obj = queryset.get() + except queryset.model.DoesNotExist: + raise Http404(_("No %(verbose_name)s found matching the query") % + {'verbose_name': queryset.model._meta.verbose_name}) + return obj + def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) if self.request.user.is_authenticated: diff --git a/web/src/components/CourseRedactor.vue b/web/src/components/CourseRedactor.vue index eaec96d4..eff51320 100644 --- a/web/src/components/CourseRedactor.vue +++ b/web/src/components/CourseRedactor.vue @@ -474,7 +474,7 @@ onCourseNameInput() { this.$v.course.title.$touch(); if (!this.slugChanged) { - this.course.url = slugify(this.course.title); + this.course.url = (slugify(this.course.title) || '').toLowerCase(); } }, removeLesson(lessonIndex) { diff --git a/web/src/js/modules/api.js b/web/src/js/modules/api.js index ed60c229..919588bd 100644 --- a/web/src/js/modules/api.js +++ b/web/src/js/modules/api.js @@ -113,7 +113,7 @@ export const api = { deferred_start_at: deferredStart, duration: courseObject.duration || 0, is_featured: courseObject.is_featured, - slug: courseObject.url, + slug: (courseObject.url || '').toLowerCase(), date: (courseObject.date) ? courseObject.date.value:null, stream: courseObject.stream, cover: courseObject.coverImageId ? courseObject.coverImageId : null, From 34b98ca540b08b934562dabd7e79c964025c1d14 Mon Sep 17 00:00:00 2001 From: gzbender Date: Wed, 16 Jan 2019 00:17:29 +0300 Subject: [PATCH 03/12] =?UTF-8?q?=D0=BF=D1=80=D0=B8=20=D1=80=D0=B5=D0=B4?= =?UTF-8?q?=D0=B0=D0=BA=D1=82=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8?= =?UTF-8?q?=D0=B8=20=D1=83=D1=80=D0=BE=D0=BA=D0=BE=D0=B2=20=D0=B2=D0=BE?= =?UTF-8?q?=D0=B7=D0=BD=D0=B8=D0=BA=D0=B0=D0=B5=D1=82=20500=20=D0=BE=D1=88?= =?UTF-8?q?=D0=B8=D0=B1=D0=BA=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/school/models.py | 2 +- apps/school/templates/school/livelessons_list.html | 2 +- apps/school/urls.py | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/school/models.py b/apps/school/models.py index 4ba85193..38889f44 100644 --- a/apps/school/models.py +++ b/apps/school/models.py @@ -147,7 +147,7 @@ class LiveLesson(BaseModel, DeactivatedMixin): return self.get_absolute_url() def get_absolute_url(self): - return reverse_lazy('school:lesson-detail', args=[self.date.strftime('%d-%m-%y')]) + return reverse_lazy('school:lesson-detail', kwargs={'lesson_date': self.date.strftime('%d-%m-%y')}) def stream_index(self): return self.stream.split('/')[-1] diff --git a/apps/school/templates/school/livelessons_list.html b/apps/school/templates/school/livelessons_list.html index 2f435dcc..161a6629 100644 --- a/apps/school/templates/school/livelessons_list.html +++ b/apps/school/templates/school/livelessons_list.html @@ -11,7 +11,7 @@ {% for livelesson in livelesson_list %}
- + diff --git a/apps/school/urls.py b/apps/school/urls.py index c36664f0..9ac1d078 100644 --- a/apps/school/urls.py +++ b/apps/school/urls.py @@ -1,4 +1,4 @@ -from django.urls import path, include +from django.urls import path, re_path from .views import ( LiveLessonsView, LiveLessonEditView, @@ -12,6 +12,6 @@ urlpatterns = [ path('lessons/', LiveLessonsView.as_view(), name='lessons'), path('lessons/create', LiveLessonEditView.as_view(), name='lessons-create'), path('lessons//edit', LiveLessonEditView.as_view(), name='lessons-edit'), - path('lessons//', LiveLessonsDetailView.as_view(), name='lesson-detail'), - path('', LiveLessonsDetailView.as_view(), name='lesson-detail'), + path('lessons//', LiveLessonsDetailView.as_view(), name='lesson-detail-id'), + re_path(r'(?P\d+\-\d+\-\d+)', LiveLessonsDetailView.as_view(), name='lesson-detail'), ] From bda2fbec216b9c8f0e6c0f8833ce23afe2f796fa Mon Sep 17 00:00:00 2001 From: gzbender Date: Fri, 18 Jan 2019 21:14:23 +0300 Subject: [PATCH 04/12] LIL-731 --- apps/content/templates/content/contest.html | 5 + .../templates/content/contest_edit.html | 8 +- apps/user/templates/user/bonus-history.html | 4 + .../user/templates/user/profile-settings.html | 4 + project/templates/lilcity/edit_index.html | 1 + web/src/components/ContestRedactor.vue | 4 - web/src/components/ContestWorks.vue | 29 +-- web/src/components/CourseRedactor.vue | 168 ------------------ web/src/components/UploadContestWork.vue | 38 ---- web/src/components/blocks/ContestWork.vue | 35 ---- web/src/js/app.js | 17 -- web/src/js/pages/contest-edit.js | 2 + web/src/js/pages/contest.js | 2 + web/src/js/pages/course-edit.js | 2 + web/src/sass/components/contest-edit.scss | 35 ++++ web/src/sass/components/contest-work.scss | 0 web/src/sass/components/contest.scss | 55 ++++++ web/src/sass/components/course-edit.scss | 166 +++++++++++++++++ web/webpack.config.js | 54 +----- 19 files changed, 285 insertions(+), 344 deletions(-) create mode 100644 web/src/sass/components/contest-edit.scss delete mode 100644 web/src/sass/components/contest-work.scss create mode 100644 web/src/sass/components/contest.scss create mode 100644 web/src/sass/components/course-edit.scss diff --git a/apps/content/templates/content/contest.html b/apps/content/templates/content/contest.html index 9edbe8ec..49a0bd19 100644 --- a/apps/content/templates/content/contest.html +++ b/apps/content/templates/content/contest.html @@ -45,3 +45,8 @@
{% endblock content %} + +{% block pre_app_js %} + + +{% endblock pre_app_js %} diff --git a/apps/content/templates/content/contest_edit.html b/apps/content/templates/content/contest_edit.html index 409405a6..856a6d9b 100644 --- a/apps/content/templates/content/contest_edit.html +++ b/apps/content/templates/content/contest_edit.html @@ -12,6 +12,8 @@ {% block content %} {% endblock content %} -{% block foot %} - -{% endblock foot %} + +{% block pre_app_js %} + + +{% endblock pre_app_js %} diff --git a/apps/user/templates/user/bonus-history.html b/apps/user/templates/user/bonus-history.html index 105592a5..ef3bf9d8 100644 --- a/apps/user/templates/user/bonus-history.html +++ b/apps/user/templates/user/bonus-history.html @@ -79,3 +79,7 @@ {% endblock content %} + +{% block pre_app_js %} + +{% endblock pre_app_js %} diff --git a/apps/user/templates/user/profile-settings.html b/apps/user/templates/user/profile-settings.html index 04eecdec..7de0e74c 100644 --- a/apps/user/templates/user/profile-settings.html +++ b/apps/user/templates/user/profile-settings.html @@ -323,3 +323,7 @@ // (new Inputmask('+7 (999) 999-99-99')).mask(document.querySelector('[name=phone]')); {% endblock foot %} + +{% block pre_app_js %} + +{% endblock pre_app_js %} diff --git a/project/templates/lilcity/edit_index.html b/project/templates/lilcity/edit_index.html index a88a7e84..074fb6e4 100644 --- a/project/templates/lilcity/edit_index.html +++ b/project/templates/lilcity/edit_index.html @@ -316,6 +316,7 @@ {% include 'templates/blocks/lil_store_js.html' %} +{% block pre_app_js %}{% endblock pre_app_js %} - - diff --git a/web/src/components/ContestWorks.vue b/web/src/components/ContestWorks.vue index b0d6f493..156acf93 100644 --- a/web/src/components/ContestWorks.vue +++ b/web/src/components/ContestWorks.vue @@ -74,8 +74,8 @@ } } } - - heights[column] += workHeight; + + heights[column] += workHeight; [first, second, third][column].push(work); index++; } @@ -112,28 +112,3 @@ components: {ContestWork}, } - - diff --git a/web/src/components/CourseRedactor.vue b/web/src/components/CourseRedactor.vue index 2bd6bd65..3cfa8030 100644 --- a/web/src/components/CourseRedactor.vue +++ b/web/src/components/CourseRedactor.vue @@ -1074,172 +1074,4 @@ } - diff --git a/web/src/components/UploadContestWork.vue b/web/src/components/UploadContestWork.vue index 326c05c4..60d5f657 100644 --- a/web/src/components/UploadContestWork.vue +++ b/web/src/components/UploadContestWork.vue @@ -153,41 +153,3 @@ } } - - diff --git a/web/src/components/blocks/ContestWork.vue b/web/src/components/blocks/ContestWork.vue index 617b9fab..2cb1def9 100644 --- a/web/src/components/blocks/ContestWork.vue +++ b/web/src/components/blocks/ContestWork.vue @@ -25,38 +25,3 @@ components: {Likes}, } - - diff --git a/web/src/js/app.js b/web/src/js/app.js index 313141c1..9301efe8 100644 --- a/web/src/js/app.js +++ b/web/src/js/app.js @@ -40,23 +40,6 @@ const components = { Comments, FAQ, }; -// -//if(window.LIL_STORE.urlIs('userProfileEdit') || window.LIL_STORE.urlIs('userBonuses')){ -// const profile = require("./modules/profile"); -// profile.main(); -//} -//if(window.LIL_STORE.urlIs(['courseEdit', 'courseCreate'])){ -// const courseEdit = require("./modules/course-redactor"); -// courseEdit.main(); -//} -//if(window.LIL_STORE.urlIs('contestEdit')){ -// const ContestRedactor = require('../components/ContestRedactor.vue'); -// components['contest-redactor'] = ContestRedactor.default; -//} -//if(window.LIL_STORE.urlIs('userGalleryEdit')){ -// const userGalleryEdit = require("./modules/user-gallery-edit"); -// userGalleryEdit.main(); -//} Object.assign(components, window.LIL_STORE.components); diff --git a/web/src/js/pages/contest-edit.js b/web/src/js/pages/contest-edit.js index e1daf8ef..95b05559 100644 --- a/web/src/js/pages/contest-edit.js +++ b/web/src/js/pages/contest-edit.js @@ -1,3 +1,5 @@ +import '../../sass/components/contest-edit.scss'; + import ContestRedactor from '../../components/ContestRedactor.vue'; window.LIL_STORE.components['contest-redactor'] = ContestRedactor; diff --git a/web/src/js/pages/contest.js b/web/src/js/pages/contest.js index d5785c15..84902ebb 100644 --- a/web/src/js/pages/contest.js +++ b/web/src/js/pages/contest.js @@ -1,3 +1,5 @@ +import '../../sass/components/contest.scss'; + import UploadContestWork from '../../components/UploadContestWork.vue'; import ContestWorks from '../../components/ContestWorks.vue'; diff --git a/web/src/js/pages/course-edit.js b/web/src/js/pages/course-edit.js index e7a2fcc4..25b1545b 100644 --- a/web/src/js/pages/course-edit.js +++ b/web/src/js/pages/course-edit.js @@ -1,3 +1,5 @@ +import '../../sass/components/course-edit.scss'; + import 'babel-polyfill'; import CourseRedactor from '../../components/CourseRedactor.vue'; import $ from 'jquery'; diff --git a/web/src/sass/components/contest-edit.scss b/web/src/sass/components/contest-edit.scss new file mode 100644 index 00000000..574739d4 --- /dev/null +++ b/web/src/sass/components/contest-edit.scss @@ -0,0 +1,35 @@ +.upload-contest-work { + + .popup__wrap { + padding: 35px 35px 0; + } + + .title { + text-align: center; font-size: 24px; + + .text__curve { + right: 55px; + width: 170px; + bottom: -40px; + } + } + + .kit__photo { + height: 400px; + } + + .kit__photo.has-image { + border: none; + } + + .kit__photo-image { + max-height: 400px; + height: auto; + width: auto; + } + + .kit__file { + bottom: 0; + } + +} diff --git a/web/src/sass/components/contest-work.scss b/web/src/sass/components/contest-work.scss deleted file mode 100644 index e69de29b..00000000 diff --git a/web/src/sass/components/contest.scss b/web/src/sass/components/contest.scss new file mode 100644 index 00000000..bc243ebf --- /dev/null +++ b/web/src/sass/components/contest.scss @@ -0,0 +1,55 @@ +.contest-works { + width: 100%; +} +.contest-works__works { + text-align: left; + display: flex; +} +.contest-works__column { + display: flex; + flex-direction: column; + margin-right: 20px; + width: 300px; +} +.contest-works__loader { + width: 100%; + height: 30px; + position: relative; +} +.contest-works__no-works { + text-align: center; + width: 100%; +} + +.contest-work-item { + break-inside: avoid; + border-radius: 8px; + overflow: hidden; + margin-bottom: 20px; + transition: opacity .4s ease-in-out; + text-transform: uppercase; + font-weight: bold; + color: black; + border: 1px solid #ececec; + display: block; +} +.contest-work-item__img { + width: 100%; + height: auto; +} +.contest-work-item__info { + display: flex; + padding: 5px 10px; +} +.contest-work-item__age { + color: #919191; +} +.contest-work-item__bio { + flex: calc(100% - 70px); +} + +@media only screen and (min-width: 1023px) { + .contest-works:hover .contest-work-item:not(:hover) { + opacity: 0.4; + } +} diff --git a/web/src/sass/components/course-edit.scss b/web/src/sass/components/course-edit.scss new file mode 100644 index 00000000..ad1d219e --- /dev/null +++ b/web/src/sass/components/course-edit.scss @@ -0,0 +1,166 @@ +.vdp-datepicker__calendar { + width: 240px; + margin-top: 10px; + padding: 5px; + background: white; + box-shadow: 0 2px 20px 0 rgba(0, 0, 0, 0.1); + z-index: 99 !important; + + header { + display: flex; + margin-bottom: 5px; + -ms-flex-align: center; + align-items: center; + } + + .prev, .next { + font-size: 0; + cursor: pointer; + order: 1; + width: auto !important; + padding: 10px; + } + + .prev { + order: 1; + } + + .next { + order: 3; + } + + .prev:before, .next:before { + content: ''; + display: block; + width: 10px; + height: 10px; + border: solid #E6E6E6; + border-width: 2px 2px 0 0; + } + + .prev:after, .next:after { + content: none !important; + } + + .prev:before { + transform: rotate(-135deg); + } + + .next:before { + transform: rotate(45deg); + } +} + +.kit__preview { + img { + width: 140px; + height: 140px; + } +} + +.kit__photo { + width: 140px; + height: 140px; +} + +.kit__section-remove { + button.sortable__handle { + margin-right: 10px; + cursor: -webkit-grab; + cursor: grab; + + svg.icon-hamburger { + width: 1em; + height: 1em; + } + } +} + +.sortable-ghost, .sortable-chosen { + background: white; + border-radius: 10px; +} + +.course-redactor__preview-button-bg-save { + background-color: #58fffb; +} +.course-redactor__preview-button { + transition: backgroundColor 0.5s ease-in-out; +} + +.field_text { + height: 270px; + overflow: scroll; +} + +.courses__item { + flex: 0 0 300px; +} + +.courses__item .field { + margin-bottom: 0; +} + +.courses__content .redactor-box { + overflow-x: visible; + overflow-y: auto; + max-height: 200px; + background: none; + margin-top: 10px; +} + +.courses__content .redactor-layer{ + background: none; +} + +.courses__theme { + flex: 1; +} + +.courses__price { + margin-left: 20px; +} + +.courses__preview { + .upload { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + } + + .upload__title { + color: #888888; + font-size: 16px; + margin-top: 100px; + width: 100%; + text-align: center; + } + + .upload__file { + width: 100%; + height: 100%; + } +} + +.course-delete-cover { + left: 5px; + position: absolute; + bottom: 3px; +} + +.field-category .select__head { + font-size: inherit; + line-height: inherit; + height: auto; +} + +.datetime-fields { + display: flex; +} + +.field-time { + margin-left: 10px; + flex: 50%; +} diff --git a/web/webpack.config.js b/web/webpack.config.js index 886156ed..21ead790 100644 --- a/web/webpack.config.js +++ b/web/webpack.config.js @@ -21,8 +21,6 @@ module.exports = { imagesGiftCertificates: glob('./src/img/gift-certificates/*'), imagesReviews: glob('./src/img/reviews/*'), fonts: glob('./src/fonts/*'), -// pages: glob('./src/js/pages/*'), -// pagesCss: glob('./src/sass/pages/*'), }, output: { path: path.join(__dirname, "build"), @@ -34,7 +32,7 @@ module.exports = { loaders: [ { test: /\.js$/, - exclude: /(node_modules|bower_components|third_party|pages)/, + exclude: /(node_modules|bower_components|third_party)/, use: { loader: 'babel-loader', options: { @@ -44,7 +42,7 @@ module.exports = { }, { test: /third_party\/.*\.js$/, - exclude: /(node_modules|bower_components|pages)/, + exclude: /(node_modules|bower_components)/, use: { loader: 'file-loader', options: { @@ -52,22 +50,6 @@ module.exports = { } } }, -// { -// test: /\.js$/, -// include: [path.resolve(__dirname, 'src/js/pages')], -// use: [{ -// loader: 'file-loader', -// options: { -// name: "[name].[ext]" -// } -// }, -// { -// loader: 'babel-loader', -// options: { -// "presets": ["es2015"], -// } -// }] -// }, { test: /\.css$/, use: ExtractTextPlugin.extract({ @@ -77,39 +59,11 @@ module.exports = { }, { test: /\.s[ac]ss$/, - exclude: [path.resolve(__dirname, 'src/sass/pages')], use: ExtractTextPlugin.extract({ fallback: 'style-loader', use: ['css-loader', 'sass-loader'] }) }, - /* { - test: /\.s[ac]ss$/, - include: [path.resolve(__dirname, 'src/sass/pages')], - use: [ - { - loader: 'file-loader', - options: { - name: '[name].css', - } - }, - { - loader: 'extract-loader', - }, - { - loader: 'css-loader', - options: { - sourceMap: true - } - }, - { - loader: 'sass-loader', - options: { - sourceMap: true - } - } - ] - }, */ { test: /\.vue$/, loader: 'vue-loader', @@ -174,10 +128,6 @@ module.exports = { "window.$": "jquery" }), new ExtractTextPlugin('[name].css'), -// new MiniCssExtractPlugin({ -// filename: "[name].css", -// chunkFilename: "[id].css" -// }), ], resolve: { From ad27a712a60cd6eb8f4861d9adbd30ae3b9af758 Mon Sep 17 00:00:00 2001 From: gzbender Date: Sun, 20 Jan 2019 22:11:56 +0300 Subject: [PATCH 05/12] =?UTF-8?q?=D0=BF=D1=80=D0=BE=D0=B2=D0=B5=D1=80?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D1=83=20?= =?UTF-8?q?=D1=81=D1=81=D1=8B=D0=BB=D0=BE=D0=BA=20=D0=BD=D0=B0=20=D0=BA?= =?UTF-8?q?=D1=83=D1=80=D1=81=D1=8B=20=D0=B2=20=D0=B0=D0=B4=D0=BC=D0=B8?= =?UTF-8?q?=D0=BD=D0=BA=D0=B5,=20=D1=81=D0=B4=D0=B5=D0=BB=D0=B0=D1=82?= =?UTF-8?q?=D1=8C=20=D0=B2=D1=81=D0=B5=20=D1=81=D1=81=D1=8B=D0=BB=D0=BA?= =?UTF-8?q?=D0=B8=20=D0=BD=D0=B0=20=D0=BA=D1=83=D1=80=D1=81=D1=8B=20=D0=BF?= =?UTF-8?q?=D0=BE=20slug=20(=D0=BC=D0=B5=D0=BD=D0=B5=D0=B4=D0=B6=D0=BC?= =?UTF-8?q?=D0=B5=D0=BD=D1=82=20=D0=BA=D0=BE=D0=BC=D0=B0=D0=BD=D0=B4=D0=BE?= =?UTF-8?q?=D0=B9)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/course/management/__init__.py | 0 apps/course/management/commands/__init__.py | 0 .../commands/update_courses_slug.py | 20 +++++++++++++++++++ apps/course/models.py | 18 ++++++++--------- 4 files changed, 29 insertions(+), 9 deletions(-) create mode 100644 apps/course/management/__init__.py create mode 100644 apps/course/management/commands/__init__.py create mode 100644 apps/course/management/commands/update_courses_slug.py diff --git a/apps/course/management/__init__.py b/apps/course/management/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/apps/course/management/commands/__init__.py b/apps/course/management/commands/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/apps/course/management/commands/update_courses_slug.py b/apps/course/management/commands/update_courses_slug.py new file mode 100644 index 00000000..24999a2e --- /dev/null +++ b/apps/course/management/commands/update_courses_slug.py @@ -0,0 +1,20 @@ +from unidecode import unidecode + +from django.core.management.base import BaseCommand, CommandError +from django.db.models import Q +from django.utils.text import slugify +from apps.course.models import Course + + +class Command(BaseCommand): + help = 'Upload users to Roistat' + + def handle(self, *args, **options): + courses = Course.objects.filter(Q(slug__isnull=True) | Q(slug='')) + for course in courses: + course.slug = slugify(unidecode(course.title[:90])) + try: + course.save() + except: + course.slug += str(course.id) + course.save() diff --git a/apps/course/models.py b/apps/course/models.py index 42a1dd81..b11156f4 100644 --- a/apps/course/models.py +++ b/apps/course/models.py @@ -1,10 +1,13 @@ import arrow from random import shuffle from uuid import uuid4 +from unidecode import unidecode + from django.db import models from django.core.exceptions import ValidationError from django.utils import timezone from django.utils.timezone import now +from django.utils.text import slugify from django.contrib.auth import get_user_model from django.urls import reverse_lazy from django.conf import settings @@ -119,17 +122,14 @@ class Course(BaseModel, DeactivatedMixin): def __str__(self): return str(self.id) + ' ' + self.title - # def save(self, *args, **kwargs): - # if not self.slug: - # self.slug = slugify( - # self.title[:90], - # allow_unicode=True - # ) + def save(self, *args, **kwargs): + if not self.slug: + self.slug = slugify(unidecode(self.title[:90])) - # if Course.objects.filter(slug=self.slug).exclude(id=self.id).exists(): - # self.slug += '_' + str(uuid4())[:6] + if Course.objects.filter(slug=self.slug).exclude(id=self.id).exists(): + self.slug += str(uuid4())[-3:] - # return super().save() + return super().save() @property def url(self): From 81bcc7e56a91f3f2907356f0533f78c2814f7b03 Mon Sep 17 00:00:00 2001 From: gzbender Date: Mon, 21 Jan 2019 15:17:27 +0300 Subject: [PATCH 06/12] =?UTF-8?q?=D0=BF=D1=80=D0=BE=D0=B2=D0=B5=D1=80?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D1=83=20?= =?UTF-8?q?=D1=81=D1=81=D1=8B=D0=BB=D0=BE=D0=BA=20=D0=BD=D0=B0=20=D0=BA?= =?UTF-8?q?=D1=83=D1=80=D1=81=D1=8B=20=D0=B2=20=D0=B0=D0=B4=D0=BC=D0=B8?= =?UTF-8?q?=D0=BD=D0=BA=D0=B5,=20=D1=81=D0=B4=D0=B5=D0=BB=D0=B0=D1=82?= =?UTF-8?q?=D1=8C=20=D0=B2=D1=81=D0=B5=20=D1=81=D1=81=D1=8B=D0=BB=D0=BA?= =?UTF-8?q?=D0=B8=20=D0=BD=D0=B0=20=D0=BA=D1=83=D1=80=D1=81=D1=8B=20=D0=BF?= =?UTF-8?q?=D0=BE=20slug=20(=D0=BC=D0=B5=D0=BD=D0=B5=D0=B4=D0=B6=D0=BC?= =?UTF-8?q?=D0=B5=D0=BD=D1=82=20=D0=BA=D0=BE=D0=BC=D0=B0=D0=BD=D0=B4=D0=BE?= =?UTF-8?q?=D0=B9)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index 6107112a..78736651 100644 --- a/requirements.txt +++ b/requirements.txt @@ -36,3 +36,4 @@ short_url sendgrid drf_dynamic_fields flower==0.9.2 +unidecode From 4ddac99775845fbb195c495b5f07645949fc5019 Mon Sep 17 00:00:00 2001 From: gzbender Date: Wed, 23 Jan 2019 23:08:36 +0500 Subject: [PATCH 07/12] =?UTF-8?q?=D0=BF=D1=80=D0=BE=D0=B2=D0=B5=D1=80?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D1=83=20?= =?UTF-8?q?=D1=81=D1=81=D1=8B=D0=BB=D0=BE=D0=BA=20=D0=BD=D0=B0=20=D0=BA?= =?UTF-8?q?=D1=83=D1=80=D1=81=D1=8B=20=D0=B2=20=D0=B0=D0=B4=D0=BC=D0=B8?= =?UTF-8?q?=D0=BD=D0=BA=D0=B5,=20=D1=81=D0=B4=D0=B5=D0=BB=D0=B0=D1=82?= =?UTF-8?q?=D1=8C=20=D0=B2=D1=81=D0=B5=20=D1=81=D1=81=D1=8B=D0=BB=D0=BA?= =?UTF-8?q?=D0=B8=20=D0=BD=D0=B0=20=D0=BA=D1=83=D1=80=D1=81=D1=8B=20=D0=BF?= =?UTF-8?q?=D0=BE=20slug=20(=D0=BC=D0=B5=D0=BD=D0=B5=D0=B4=D0=B6=D0=BC?= =?UTF-8?q?=D0=B5=D0=BD=D1=82=20=D0=BA=D0=BE=D0=BC=D0=B0=D0=BD=D0=B4=D0=BE?= =?UTF-8?q?=D0=B9)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/course/models.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/apps/course/models.py b/apps/course/models.py index b11156f4..b2233bd4 100644 --- a/apps/course/models.py +++ b/apps/course/models.py @@ -124,10 +124,11 @@ class Course(BaseModel, DeactivatedMixin): def save(self, *args, **kwargs): if not self.slug: - self.slug = slugify(unidecode(self.title[:90])) - - if Course.objects.filter(slug=self.slug).exclude(id=self.id).exists(): - self.slug += str(uuid4())[-3:] + slug = slugify(unidecode(self.title[:90])) + self.slug = slug + if self.slug: + while Course.objects.filter(slug=self.slug).exclude(id=self.id).exists(): + self.slug = slug + str(uuid4())[-4:] return super().save() From 4541acbaad5ed003a48b53e628bd42eea616d5b3 Mon Sep 17 00:00:00 2001 From: gzbender Date: Thu, 24 Jan 2019 11:38:56 +0500 Subject: [PATCH 08/12] =?UTF-8?q?=D0=BF=D1=80=D0=BE=D0=B2=D0=B5=D1=80?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D1=83=20?= =?UTF-8?q?=D1=81=D1=81=D1=8B=D0=BB=D0=BE=D0=BA=20=D0=BD=D0=B0=20=D0=BA?= =?UTF-8?q?=D1=83=D1=80=D1=81=D1=8B=20=D0=B2=20=D0=B0=D0=B4=D0=BC=D0=B8?= =?UTF-8?q?=D0=BD=D0=BA=D0=B5,=20=D1=81=D0=B4=D0=B5=D0=BB=D0=B0=D1=82?= =?UTF-8?q?=D1=8C=20=D0=B2=D1=81=D0=B5=20=D1=81=D1=81=D1=8B=D0=BB=D0=BA?= =?UTF-8?q?=D0=B8=20=D0=BD=D0=B0=20=D0=BA=D1=83=D1=80=D1=81=D1=8B=20=D0=BF?= =?UTF-8?q?=D0=BE=20slug=20(=D0=BC=D0=B5=D0=BD=D0=B5=D0=B4=D0=B6=D0=BC?= =?UTF-8?q?=D0=B5=D0=BD=D1=82=20=D0=BA=D0=BE=D0=BC=D0=B0=D0=BD=D0=B4=D0=BE?= =?UTF-8?q?=D0=B9)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/course/models.py | 12 ++++---- web/src/components/CourseRedactor.vue | 41 +++++---------------------- web/src/js/modules/api.js | 4 +-- 3 files changed, 16 insertions(+), 41 deletions(-) diff --git a/apps/course/models.py b/apps/course/models.py index b2233bd4..0c33fd81 100644 --- a/apps/course/models.py +++ b/apps/course/models.py @@ -124,11 +124,13 @@ class Course(BaseModel, DeactivatedMixin): def save(self, *args, **kwargs): if not self.slug: - slug = slugify(unidecode(self.title[:90])) - self.slug = slug - if self.slug: - while Course.objects.filter(slug=self.slug).exclude(id=self.id).exists(): - self.slug = slug + str(uuid4())[-4:] + self.slug = slugify(unidecode(self.title[:90])) + if self.slug: + if self.slug.isdigit(): + self.slug = 'course%s' % self.slug + slug = self.slug + while Course.objects.filter(slug__iexact=self.slug).exclude(id=self.id).exists(): + self.slug = '%s_%s' % (slug, str(uuid4())[-4:]) return super().save() diff --git a/web/src/components/CourseRedactor.vue b/web/src/components/CourseRedactor.vue index c16a0a4b..b705382b 100644 --- a/web/src/components/CourseRedactor.vue +++ b/web/src/components/CourseRedactor.vue @@ -45,7 +45,7 @@
ССЫЛКА
- +
{{ courseFullUrl }}
@@ -273,6 +273,7 @@ price: null, old_price: null, age: 0, + slug: '', url: '', coverImage: '', kit__body: null, @@ -473,8 +474,8 @@ }, onCourseNameInput() { this.$v.course.title.$touch(); - if (!this.slugChanged) { - this.course.url = slugify(this.course.title); + if (!this.slugChanged && !this.$v.course.status) { + this.course.slug = slugify(this.course.title); } }, removeLesson(lessonIndex) { @@ -741,24 +742,6 @@ } }, saveCourseDraft: function (newValue, oldValue) { - //console.log('saveCourseDraft'); - // if (!oldValue.id) { - // return; - // } - - - // if(this.live) { - // if(!this.course.date || this.course.short_description == '' || this.course.title == '') { - // //console.log('live valiedation error'); - // return; - // } - // } else { - // if(this.course.short_description == '' || this.course.title == '') { - // //console.log('course validation error'); - // return; - // } - // } - if (this.savingDebounceTimeout) { clearTimeout(this.savingDebounceTimeout); } @@ -771,13 +754,14 @@ this.courseSaving = true; this.changeSavingStatus(); const courseObject = this.course; - courseObject.url = (courseObject.url) ? slugify(courseObject.url):courseObject.url; + courseObject.slug = courseObject.slug && slugify(courseObject.slug); api.saveCourse(courseObject, this.accessToken) .then((response) => { this.courseSaving = false; this.changeSavingStatus(true); this.courseSyncHook = true; const courseData = api.convertCourseJson(response.data); + this.course.slug = courseData.slug; if (this.course.coverImage) { courseData.coverImage = this.course.coverImage; } @@ -804,19 +788,11 @@ }) } }); - if (courseData.url) { - this.slugChanged = true; - } if(courseData.id) { this.course.id = courseData.id; } - /*if(this.live && courseData.date) { - this.course.date = _.find(this.scheduleOptions, function(item){ - return item.value == courseData.date; - }); - }*/ this.$nextTick(() => { this.courseSyncHook = false; }); @@ -1029,10 +1005,7 @@ } }, courseFullUrl() { - if (!this.course.url) { - return `https://lil.city/course/${this.course.id}`; - } - let suffix = this.course.url ? this.course.url : 'ваша_ссылка'; + let suffix = this.course.slug || this.course.id || 'ваша_ссылка'; return `https://lil.city/course/${suffix}`; }, }, diff --git a/web/src/js/modules/api.js b/web/src/js/modules/api.js index ed60c229..929696fd 100644 --- a/web/src/js/modules/api.js +++ b/web/src/js/modules/api.js @@ -113,7 +113,7 @@ export const api = { deferred_start_at: deferredStart, duration: courseObject.duration || 0, is_featured: courseObject.is_featured, - slug: courseObject.url, + slug: courseObject.slug, date: (courseObject.date) ? courseObject.date.value:null, stream: courseObject.stream, cover: courseObject.coverImageId ? courseObject.coverImageId : null, @@ -194,7 +194,7 @@ export const api = { time: deferredTime, duration: courseJSON.duration, is_featured: courseJSON.is_featured, - url: courseJSON.slug, + slug: courseJSON.slug, stream: courseJSON.stream, coverImageId: courseJSON.cover && courseJSON.cover.id ? courseJSON.cover.id : null, coverImage: courseJSON.cover && courseJSON.cover.image ? courseJSON.cover.image : null, From fc1fd4d1846197abe96bae3fa66265e6c66f223b Mon Sep 17 00:00:00 2001 From: gzbender Date: Thu, 24 Jan 2019 20:49:48 +0500 Subject: [PATCH 09/12] =?UTF-8?q?=D0=BF=D1=83=D1=81=D1=82=D0=BE=D0=B9=20fa?= =?UTF-8?q?q?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/content/admin.py | 7 ++++++- web/src/js/app.js | 6 +++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/apps/content/admin.py b/apps/content/admin.py index c025f198..c38b753d 100644 --- a/apps/content/admin.py +++ b/apps/content/admin.py @@ -8,7 +8,7 @@ from polymorphic.admin import ( from apps.content.models import ( Baner, Content, Image, Text, ImageText, Video, Gallery, GalleryImage, ImageObject, - Contest,ContestWork, + Contest, ContestWork, FAQ, ) @@ -90,3 +90,8 @@ class ContestAdmin(admin.ModelAdmin): @admin.register(ContestWork) class ContestWorkAdmin(admin.ModelAdmin): base_model = ContestWork + + +@admin.register(FAQ) +class FAQAdmin(admin.ModelAdmin): + base_model = FAQ diff --git a/web/src/js/app.js b/web/src/js/app.js index 9301efe8..8b6be846 100644 --- a/web/src/js/app.js +++ b/web/src/js/app.js @@ -36,9 +36,9 @@ if (process.env.NODE_ENV === 'development') { } const components = { - Likes, - Comments, - FAQ, + 'likes': Likes, + 'comments': Comments, + 'faq': FAQ, }; Object.assign(components, window.LIL_STORE.components); From a522267914ab67ecf761b565a463704190362b8d Mon Sep 17 00:00:00 2001 From: gzbender Date: Thu, 24 Jan 2019 22:58:54 +0500 Subject: [PATCH 10/12] =?UTF-8?q?=D0=BF=D1=80=D0=B0=D0=B2=D0=BA=D0=B8=20?= =?UTF-8?q?=D0=BA=D0=BE=D0=BC=D0=BC=D0=B5=D0=BD=D1=82=D0=B0=D1=80=D0=B8?= =?UTF-8?q?=D0=B5=D0=B2=20=D0=BF=D1=80=D0=B8=20=D0=BD=D0=B5=D0=B0=D0=B2?= =?UTF-8?q?=D1=82=D0=BE=D1=80=D0=B8=D0=B7=D0=BE=D0=B2=D0=B0=D0=BD=D0=BD?= =?UTF-8?q?=D0=BE=D0=BC=20=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0?= =?UTF-8?q?=D1=82=D0=B5=D0=BB=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/course/templates/course/course.html | 3 +-- apps/course/templates/course/course_only_lessons.html | 2 +- apps/course/templates/course/lesson.html | 2 +- web/src/components/Comments.vue | 3 +++ 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/apps/course/templates/course/course.html b/apps/course/templates/course/course.html index 94fd1938..bf57e971 100644 --- a/apps/course/templates/course/course.html +++ b/apps/course/templates/course/course.html @@ -335,8 +335,7 @@
- -
Задавайте вопросы:
+
{% if request.user.is_authenticated %}Задавайте вопросы:{% else %}Комментарии:{% endif %}
diff --git a/apps/course/templates/course/course_only_lessons.html b/apps/course/templates/course/course_only_lessons.html index d56e641e..3a9aeae7 100644 --- a/apps/course/templates/course/course_only_lessons.html +++ b/apps/course/templates/course/course_only_lessons.html @@ -192,7 +192,7 @@ {% endif %}
-
Задавайте вопросы:
+
{% if request.user.is_authenticated %}Задавайте вопросы:{% else %}Комментарии:{% endif %}
diff --git a/apps/course/templates/course/lesson.html b/apps/course/templates/course/lesson.html index e4f083f0..0c33cf6b 100644 --- a/apps/course/templates/course/lesson.html +++ b/apps/course/templates/course/lesson.html @@ -113,7 +113,7 @@ {% endcomment %}
-
Задавайте вопросы:
+
{% if request.user.is_authenticated %}Задавайте вопросы:{% else %}Комментарии:{% endif %}
diff --git a/web/src/components/Comments.vue b/web/src/components/Comments.vue index 2fd5bbb4..9b4e0f6b 100644 --- a/web/src/components/Comments.vue +++ b/web/src/components/Comments.vue @@ -7,6 +7,7 @@ +
Авторизуйтесь и оставьте первый комментарий!
@@ -26,6 +27,7 @@ nodes: [], controller: this, flatComments: {}, + noComments: false, } }, methods: { @@ -119,6 +121,7 @@ .then((response) => { vm.loading = false; vm.nodes = response.data; + vm.noComments = ! vm.nodes.length; vm.connectToPusher(); }) .catch(() => { From 9f37761e64e868fe4acc784241cfbe255c098405 Mon Sep 17 00:00:00 2001 From: gzbender Date: Fri, 25 Jan 2019 18:41:56 +0500 Subject: [PATCH 11/12] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D1=82=D1=8C=20=D0=B2=D0=BE=D0=B7=D0=BC=D0=BE=D0=B6=D0=BD=D0=BE?= =?UTF-8?q?=D1=81=D1=82=D1=8C=20=D0=BF=D1=80=D0=BE=D1=81=D0=BB=D0=B5=D0=B4?= =?UTF-8?q?=D0=B8=D1=82=D1=8C,=20=D0=BA=D1=82=D0=BE=20=D0=BF=D0=BE=D1=81?= =?UTF-8?q?=D0=BB=D0=B5=20=D0=BF=D1=80=D0=BE=D1=81=D0=BC=D0=BE=D1=82=D1=80?= =?UTF-8?q?=D0=B0=20=D0=BF=D1=80=D0=BE=D0=B1=D0=BD=D0=BE=D0=B3=D0=BE=20?= =?UTF-8?q?=D1=83=D1=80=D0=BE=D0=BA=D0=B0=20=D0=BF=D1=80=D0=B8=D0=BE=D0=B1?= =?UTF-8?q?=D1=80=D1=91=D0=BB=20=D1=88=D0=BA=D0=BE=D0=BB=D1=83=20(=D0=B2?= =?UTF-8?q?=D0=BE=D0=B7=D0=BC=D0=BE=D0=B6=D0=BD=D0=BE=20=D0=B4=D0=BE=D0=B1?= =?UTF-8?q?=D0=B0=D0=B2=D0=B8=D1=82=D1=8C=20=D0=BB=D0=BE=D0=B3=20=D0=B4?= =?UTF-8?q?=D0=BB=D1=8F=20=D0=B2=D1=81=D0=B5=D1=85=20=D0=B5=D0=BC=D0=B5?= =?UTF-8?q?=D0=B9=D0=BB=D0=BE=D0=B2)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/v1/views.py | 7 ++++++- apps/course/templates/course/_items.html | 3 ++- apps/user/admin.py | 7 ++++++- apps/user/migrations/0029_emaillog.py | 22 ++++++++++++++++++++++ apps/user/models.py | 11 +++++++++++ 5 files changed, 47 insertions(+), 3 deletions(-) create mode 100644 apps/user/migrations/0029_emaillog.py diff --git a/api/v1/views.py b/api/v1/views.py index c2b43019..1122282d 100644 --- a/api/v1/views.py +++ b/api/v1/views.py @@ -71,7 +71,7 @@ from apps.payment.models import ( CoursePayment, SchoolPayment, UserBonus, ) from apps.school.models import SchoolSchedule, LiveLesson -from apps.user.models import AuthorRequest +from apps.user.models import AuthorRequest, EmailLog from project.pusher import pusher from project.sengrid import get_sendgrid_client @@ -694,6 +694,11 @@ class CaptureEmail(views.APIView): email = request.data.get('email') sg = get_sendgrid_client() + if not email: + return Response({'error': 'No email'}, status=status.HTTP_400_BAD_REQUEST) + + EmailLog.objects.create(email=email, source=EmailLog.SOURCE_TRIAL_LESSON) + # берем все списки response = sg.client.contactdb.lists.get() if response.status_code != 200: diff --git a/apps/course/templates/course/_items.html b/apps/course/templates/course/_items.html index a5bfa123..acbccf69 100644 --- a/apps/course/templates/course/_items.html +++ b/apps/course/templates/course/_items.html @@ -53,7 +53,8 @@ {% if course.old_price %}
{{ course.old_price|floatformat:"-2" }}₽
{% endif %} -
{{ course.price|floatformat:"-2" }}₽
+
{{ course.price|floatformat:"-2" }}₽
{% endif %}
{{ course.title }} diff --git a/apps/user/admin.py b/apps/user/admin.py index df3e01d9..63398df0 100644 --- a/apps/user/admin.py +++ b/apps/user/admin.py @@ -3,7 +3,7 @@ from django.contrib.auth import get_user_model from django.contrib.auth.admin import UserAdmin as BaseUserAdmin from django.utils.translation import gettext_lazy as _ -from .models import AuthorRequest, EmailSubscription, SubscriptionCategory +from .models import AuthorRequest, EmailSubscription, SubscriptionCategory, EmailLog User = get_user_model() @@ -47,3 +47,8 @@ class EmailSubscriptionAdmin(admin.ModelAdmin): 'user', 'email', ) + + +@admin.register(EmailLog) +class EmailLogAdmin(admin.ModelAdmin): + pass diff --git a/apps/user/migrations/0029_emaillog.py b/apps/user/migrations/0029_emaillog.py new file mode 100644 index 00000000..ed154689 --- /dev/null +++ b/apps/user/migrations/0029_emaillog.py @@ -0,0 +1,22 @@ +# Generated by Django 2.0.7 on 2019-01-25 08:18 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('user', '0028_auto_20181214_0107'), + ] + + operations = [ + migrations.CreateModel( + name='EmailLog', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('email', models.EmailField(max_length=254, verbose_name='email address')), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('source', models.PositiveSmallIntegerField(choices=[(1, 'Пробный урок')])), + ], + ), + ] diff --git a/apps/user/models.py b/apps/user/models.py index 9ab545e7..5a7337bd 100644 --- a/apps/user/models.py +++ b/apps/user/models.py @@ -304,3 +304,14 @@ class Referral(models.Model): from apps.payment.models import UserBonus UserBonus.objects.create(user=self.referral, amount=referral_bonus, payment=self.payment, referral=self) UserBonus.objects.create(user=self.referrer, amount=referrer_bonus, payment=self.payment, referral=self) + + +class EmailLog(models.Model): + SOURCE_TRIAL_LESSON = 1 + SOURCE_CHOICES = ( + (SOURCE_TRIAL_LESSON, 'Пробный урок'), + ) + + email = models.EmailField(_('email address')) + created_at = models.DateTimeField(auto_now_add=True) + source = models.PositiveSmallIntegerField(choices=SOURCE_CHOICES) From 9576c3cd25c70ffdac3aff281a8a7f0d6be6567e Mon Sep 17 00:00:00 2001 From: gzbender Date: Sun, 27 Jan 2019 23:25:40 +0500 Subject: [PATCH 12/12] =?UTF-8?q?=D0=BF=D1=80=D0=BE=D0=B1=D0=BB=D0=B5?= =?UTF-8?q?=D0=BC=D0=B0=20=D1=81=20=D1=81=D0=BE=D1=85=D1=80=D0=B0=D0=BD?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=D0=BC=20=D1=81=D0=BE=D0=B4=D0=B5=D1=80?= =?UTF-8?q?=D0=B6=D0=B8=D0=BC=D0=BE=D0=B3=D0=BE=20=D0=BA=D1=83=D1=80=D1=81?= =?UTF-8?q?=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/course/templates/course/course_edit.html | 9 +++++++++ project/templates/lilcity/edit_index.html | 7 ++----- web/src/components/CourseRedactor.vue | 7 ++++--- web/src/js/modules/api.js | 5 +++-- 4 files changed, 18 insertions(+), 10 deletions(-) diff --git a/apps/course/templates/course/course_edit.html b/apps/course/templates/course/course_edit.html index 296f8da1..83990c00 100644 --- a/apps/course/templates/course/course_edit.html +++ b/apps/course/templates/course/course_edit.html @@ -7,6 +7,15 @@ Создание {% if live == 'true' %}стрима{% else %}курса{% endif %} {% endif %} {% endblock title%} + +{% block header_buttons %} + {% if live == 'true' %} + + {% else %} + + {% endif %} +{% endblock header_buttons %} + {% block content %} - {% if live == 'true' %} - - {% else %} - - {% endif %} + {% block header_buttons %} + {% endblock header_buttons %} {% include 'templates/blocks/user_menu.html' %} diff --git a/web/src/components/CourseRedactor.vue b/web/src/components/CourseRedactor.vue index b705382b..d2c7fddc 100644 --- a/web/src/components/CourseRedactor.vue +++ b/web/src/components/CourseRedactor.vue @@ -34,7 +34,8 @@ v-model="course.title" placeholder="Добавить заголовок"> -
+
@@ -663,7 +664,7 @@ if(this.live) { window.location = '/school/lessons'; } else { - api.publishCourse(this.course.id, this.accessToken) + api.publishCourse(this.course, this.accessToken) .then((response) => { window.location = '/course/on-moderation'; }) @@ -1006,7 +1007,7 @@ }, courseFullUrl() { let suffix = this.course.slug || this.course.id || 'ваша_ссылка'; - return `https://lil.city/course/${suffix}`; + return `https://lil.school/course/${suffix}`; }, }, beforeDestroy() { diff --git a/web/src/js/modules/api.js b/web/src/js/modules/api.js index 929696fd..c9627aac 100644 --- a/web/src/js/modules/api.js +++ b/web/src/js/modules/api.js @@ -437,8 +437,9 @@ export const api = { } }); }, - publishCourse: (courseId, accessToken) => { - return api.patch(`/api/v1/courses/${courseId}/`, {status: 1}, { + publishCourse: (course, accessToken) => { + course.status = 1; + return api.patch(`/api/v1/courses/${course.id}/`, course, { headers: { 'Authorization': `Token ${accessToken}`, }