remotes/origin/editis_13-01-19
gzbender 7 years ago
parent 5b603b69bf
commit e1be03f25a
  1. 14
      api/v1/serializers/mixins.py
  2. 31
      api/v1/serializers/user.py
  3. 3
      api/v1/urls.py
  4. 11
      api/v1/views.py
  5. 27
      apps/user/templates/user/edit_gallery.html
  6. 14
      web/src/components/blocks/BlockImages.vue
  7. 47
      web/src/js/app.js
  8. 26
      web/src/js/modules/api.js
  9. 1
      web/webpack.config.js

@ -131,7 +131,7 @@ class DispatchMaterialMixin(object):
class DispatchGalleryMixin(object): class DispatchGalleryMixin(object):
def dispatch_gallery(self, course, gallery): def dispatch_gallery(self, obj, gallery):
if gallery: if gallery:
if 'id' in gallery and gallery['id']: if 'id' in gallery and gallery['id']:
g = Gallery.objects.get(id=gallery['id']) g = Gallery.objects.get(id=gallery['id'])
@ -145,15 +145,19 @@ class DispatchGalleryMixin(object):
) )
if 'images' in gallery: if 'images' in gallery:
for image in gallery['images']: for image in gallery['images']:
if isinstance(image['img'], ImageObject):
img = image['img']
else:
img = ImageObject.objects.get(id=image['img'])
if 'id' in image and image['id']: if 'id' in image and image['id']:
gi = GalleryImage.objects.get(id=image['id']) gi = GalleryImage.objects.get(id=image['id'])
gi.gallery = g gi.gallery = g
gi.img = image['img'] gi.img = img
gi.save() gi.save()
else: else:
gi = GalleryImage.objects.create( gi = GalleryImage.objects.create(
gallery=g, gallery=g,
img=image['img'], img=img,
) )
course.gallery = g obj.gallery = g
course.save() obj.save()

@ -3,8 +3,10 @@ from rest_framework import serializers
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from api.v1.serializers.content import GallerySerializer, GalleryImageSerializer, GalleryImageCreateSerializer
from . import Base64ImageField from . import Base64ImageField
from apps.user.models import AuthorRequest from apps.user.models import AuthorRequest
from .mixins import DispatchGalleryMixin
User = get_user_model() User = get_user_model()
@ -104,3 +106,32 @@ class AuthorRequestSerializer(serializers.ModelSerializer):
'created_at', 'created_at',
'update_at', 'update_at',
) )
class UserGallerySerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = (
'gallery',
)
class UserGalleryUpdateSerializer(DispatchGalleryMixin, serializers.ModelSerializer):
images = serializers.ListField()
class Meta:
model = User
fields = (
'images',
)
def update(self, instance, validated_data):
images = validated_data.pop('images', {})
self.dispatch_gallery(instance, {
'id': instance.gallery_id,
'images': images,
})
return instance
def to_representation(self, instance):
return UserGallerySerializer(instance=instance, context=self.context).to_representation(instance)

@ -19,7 +19,7 @@ from .views import (
SchoolScheduleViewSet, LiveLessonViewSet, SchoolScheduleViewSet, LiveLessonViewSet,
PaymentViewSet, ObjectCommentsViewSet, PaymentViewSet, ObjectCommentsViewSet,
ContestViewSet, ContestWorkViewSet, ContestViewSet, ContestWorkViewSet,
AuthorBalanceUsersViewSet, CaptureEmail) AuthorBalanceUsersViewSet, CaptureEmail, UserGalleryViewSet)
router = DefaultRouter() router = DefaultRouter()
router.register(r'author-requests', AuthorRequestViewSet, base_name='author-requests') router.register(r'author-requests', AuthorRequestViewSet, base_name='author-requests')
@ -45,6 +45,7 @@ router.register(r'gallery-images', GalleryImageViewSet, base_name='gallery-image
router.register(r'school-schedules', SchoolScheduleViewSet, base_name='school-schedules') router.register(r'school-schedules', SchoolScheduleViewSet, base_name='school-schedules')
router.register(r'users', UserViewSet, base_name='users') router.register(r'users', UserViewSet, base_name='users')
router.register(r'user-gallery', UserGalleryViewSet, base_name='user-gallery')
router.register(r'contests', ContestViewSet, base_name='contests') router.register(r'contests', ContestViewSet, base_name='contests')
router.register(r'contest-works', ContestWorkViewSet, base_name='contest_works') router.register(r'contest-works', ContestWorkViewSet, base_name='contest_works')

@ -4,7 +4,7 @@ from decimal import Decimal
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django.db.models import Q from django.db.models import Q
from rest_framework import status, views, viewsets, generics from rest_framework import status, views, viewsets, generics, mixins
from rest_framework.decorators import detail_route, list_route, action, permission_classes, authentication_classes from rest_framework.decorators import detail_route, list_route, action, permission_classes, authentication_classes
from rest_framework.response import Response from rest_framework.response import Response
@ -42,7 +42,7 @@ from .serializers.payment import (
from .serializers.user import ( from .serializers.user import (
AuthorRequestSerializer, AuthorRequestSerializer,
UserSerializer, UserPhotoSerializer, UserSerializer, UserPhotoSerializer,
) UserGallerySerializer, UserGalleryUpdateSerializer)
from .serializers.contest import ( from .serializers.contest import (
ContestCreateSerializer, ContestSerializer, ContestWorkSerializer, ContestWorkCreateSerializer ContestCreateSerializer, ContestSerializer, ContestWorkSerializer, ContestWorkCreateSerializer
) )
@ -475,6 +475,13 @@ class UserViewSet(ExtendedModelViewSet):
return Response({'success': False}, status=status.HTTP_400_BAD_REQUEST) return Response({'success': False}, status=status.HTTP_400_BAD_REQUEST)
class UserGalleryViewSet(mixins.UpdateModelMixin, viewsets.GenericViewSet):
queryset = User.objects.all()
serializer_class = UserGalleryUpdateSerializer
# FIXME
authentication_classes = []
class SchoolScheduleViewSet(ExtendedModelViewSet): class SchoolScheduleViewSet(ExtendedModelViewSet):
queryset = SchoolSchedule.objects.all() queryset = SchoolSchedule.objects.all()
serializer_class = SchoolScheduleSerializer serializer_class = SchoolScheduleSerializer

@ -1,15 +1,34 @@
{% extends "templates/lilcity/index.html" %} {% extends "templates/lilcity/index.html" %}
{% load static %}
{% block head %}
{{ block.super }}
<style>
.kit__photo {
width: 140px;
height: 140px;
}
</style>
{% endblock head %}
{% block pre_app_js %} {% block pre_app_js %}
<script> <script>
window.LIL_STORE.components['block-images'] = '../components/BlockImages.vue';
window.LIL_STORE._user_gallery_images = [{% for img in user.gallery.gallery_images.all %}{ window.LIL_STORE._user_gallery_images = [{% for img in user.gallery.gallery_images.all %}{
image_thumbnail_url: '{{ img.image_thumbnail_url }}', id: {{ img.id }},
image_id: {{ img.id }}, image_thumbnail_url: '{{ img.img.image_thumbnail.url }}',
image_id: {{ img.img.id }},
},{% endfor %}]; },{% endfor %}];
</script> </script>
<script src="{% static 'userGalleryEdit.js' %}"></script>
{% endblock pre_app_js %} {% endblock pre_app_js %}
{% block content %} {% block content %}
<block-images :images="$root.store._user_gallery_images" :access-token="$root.store.accessToken"/> <div class="section section_gray">
<div class="section__center center center_sm">
<div>
<block-images :images="$root.store._user_gallery_images" :access-token="$root.store.accessToken" no-title="1"/>
</div>
<a href="#" id="gallery-save" class="btn">Сохранить</a>
</div>
</div>
{% endblock %} {% endblock %}

@ -1,6 +1,6 @@
<template> <template>
<div> <div>
<div class="kit__field field"> <div v-if="! noTitle" class="kit__field field">
<div class="field__wrap field__wrap--title"> <div class="field__wrap field__wrap--title">
<input :readonly="readOnly" type="text" <input :readonly="readOnly" type="text"
:value="title" :value="title"
@ -33,7 +33,7 @@
export default { export default {
name: "block-images", name: "block-images",
props: ["index", "title", "images", "accessToken", "readOnly", "longSide"], props: ["index", "title", "images", "accessToken", "readOnly", "longSide", "noTitle"],
methods: { methods: {
onTitleChange(event) { onTitleChange(event) {
this.$emit('update:title', event.target.value); this.$emit('update:title', event.target.value);
@ -46,7 +46,6 @@
let images = this.images; let images = this.images;
images.push({ images.push({
src: reader.result,
loading: true, loading: true,
}); });
this.$emit('update:images', images); this.$emit('update:images', images);
@ -59,15 +58,6 @@
images[index].loading = false; images[index].loading = false;
images[index].image_url = response.data.image; images[index].image_url = response.data.image;
images[index].image_thumbnail_url = response.data.image_thumbnail; images[index].image_thumbnail_url = response.data.image_thumbnail;
/* images.forEach((image, index) => {
if (image.src === reader.result) {
images[index].image_id = response.data.id;
images[index].loading = false;
images[index].image_url = response.data.image;
images[index].image_thumbnail_url = response.data.image_thumbnail;
}
}); */
this.$emit('update:images', images); this.$emit('update:images', images);
}) })
.catch((error) => { .catch((error) => {

@ -46,33 +46,22 @@ const components = {
Object.assign(components, window.LIL_STORE.components); Object.assign(components, window.LIL_STORE.components);
const promises = []; const app = new Vue({
el: '#lilcity-vue-app',
data() {
(async () => { return {
for(let k in components){ store: window.LIL_STORE,
if(typeof components[k] === 'string'){ }
components[k] = await import(components[k]); },
} mounted(){
} if(this.urlIs('userProfileEdit') || this.urlIs('userBonuses')){
const app = new Vue({ profileMain(this);
el: '#lilcity-vue-app', }
data() { },
return { methods: {
store: window.LIL_STORE, urlIs(urlPatternName){
} return window.location.pathname.search(this.store.urls[urlPatternName]) > -1;
},
mounted(){
if(this.urlIs('userProfileEdit') || this.urlIs('userBonuses')){
profileMain(this);
}
}, },
methods: { },
urlIs(urlPatternName){ components: components
return window.location.pathname.search(this.store.urls[urlPatternName]) > -1; });
},
},
components: components
});
})();

@ -199,6 +199,14 @@ export const api = {
gallery: {images: (courseJSON.gallery) ? courseJSON.gallery.gallery_images:[]}, gallery: {images: (courseJSON.gallery) ? courseJSON.gallery.gallery_images:[]},
} }
}, },
convertGalleryImagesJson: (images) => {
return images.map((galleryImage) => {
return {
'id': galleryImage.id ? galleryImage.id : null,
'img': galleryImage.image_id,
}
});
},
convertContentJson: (contentJson, forSaving) => { convertContentJson: (contentJson, forSaving) => {
if(forSaving){ if(forSaving){
return contentJson.map((block, index) => { return contentJson.map((block, index) => {
@ -244,12 +252,7 @@ export const api = {
'uuid': block.uuid, 'uuid': block.uuid,
'position': ++index, 'position': ++index,
'title': block.data.title, 'title': block.data.title,
'images': block.data.images.map((galleryImage) => { 'images': api.convertGalleryImagesJson(block.data.images),
return {
'id': galleryImage.id ? galleryImage.id : null,
'img': galleryImage.image_id,
}
}),
} }
} }
} else if (block.type === 'video') { } else if (block.type === 'video') {
@ -486,5 +489,14 @@ export const api = {
'Authorization': `Token ${window.LIL_STORE.accessToken}`, 'Authorization': `Token ${window.LIL_STORE.accessToken}`,
} }
}); });
} },
saveUserGallery: (images) => {
return api.patch(`/api/v1/user-gallery/${window.LIL_STORE.user.id}/`, {
images: api.convertGalleryImagesJson(images),
}, {
headers: {
'Authorization': `Token ${window.LIL_STORE.accessToken}`,
}
});
},
}; };

@ -10,6 +10,7 @@ module.exports = {
app: "./src/js/app.js", app: "./src/js/app.js",
courseRedactor: "./src/js/course-redactor.js", courseRedactor: "./src/js/course-redactor.js",
contestRedactor: "./src/js/contest-redactor.js", contestRedactor: "./src/js/contest-redactor.js",
userGalleryEdit: "./src/js/user-gallery-edit.js",
mixpanel: "./src/js/third_party/mixpanel-2-latest.js", mixpanel: "./src/js/third_party/mixpanel-2-latest.js",
sprite: glob('./src/icons/*.svg'), sprite: glob('./src/icons/*.svg'),
images: glob('./src/img/*.*'), images: glob('./src/img/*.*'),

Loading…
Cancel
Save