Commit 7801bd50068387480e54d25ec90456402b6babab

Authored by Zambom
1 parent a90d38e6

Adding post creation

amadeus/static/css/base/amadeus.css
... ... @@ -968,4 +968,13 @@ li.item .notify_badge {
968 968 .mural .post_make .post-field h4 {
969 969 cursor: text;
970 970 font-style: italic;
  971 +}
  972 +
  973 +.post_action i {
  974 + font-size: 45px;
  975 +}
  976 +
  977 +.post-button {
  978 + padding-right: inherit !important;
  979 + padding-left: inherit !important;
971 980 }
972 981 \ No newline at end of file
... ...
amadeus/static/css/themes/green.css
... ... @@ -504,6 +504,10 @@ a.add-row {
504 504 color: #CCCCCC;
505 505 }
506 506  
  507 +.post_action i {
  508 + color: #1d8fe0;
  509 +}
  510 +
507 511 @media(max-width: 768px) {
508 512 .navbar .navbar-nav .dropdown .dropdown-menu li > a {
509 513 color: #333333 !important;
... ...
mural/forms.py
... ... @@ -0,0 +1,41 @@
  1 +# coding=utf-8
  2 +from django import forms
  3 +from django.utils.translation import ugettext_lazy as _
  4 +from django.utils.html import strip_tags
  5 +
  6 +from .models import GeneralPost
  7 +
  8 +class Validation(forms.ModelForm):
  9 + MAX_UPLOAD_SIZE = 5*1024*1024
  10 +
  11 + def clean_post(self):
  12 + post = self.cleaned_data.get('post', '')
  13 + cleaned_post = strip_tags(post)
  14 +
  15 + if cleaned_post == '':
  16 + self._errors['post'] = [_('This field is required.')]
  17 +
  18 + return ValueError
  19 +
  20 + return post
  21 +
  22 + def clean_image(self):
  23 + image = self.cleaned_data.get('image', False)
  24 +
  25 + if image:
  26 + if hasattr(image, '_size'):
  27 + if image._size > self.MAX_UPLOAD_SIZE:
  28 + self._errors['image'] = [_("The image is too large. It should have less than 5MB.")]
  29 +
  30 + return ValueError
  31 +
  32 + return image
  33 +
  34 +class GeneralPostForm(Validation):
  35 + class Meta:
  36 + model = GeneralPost
  37 + fields = ['action', 'post', 'image']
  38 + widgets = {
  39 + 'action': forms.RadioSelect,
  40 + 'post': forms.Textarea
  41 + }
0 42 \ No newline at end of file
... ...
mural/migrations/0003_auto_20170204_1625.py 0 → 100644
... ... @@ -0,0 +1,20 @@
  1 +# -*- coding: utf-8 -*-
  2 +# Generated by Django 1.10 on 2017-02-04 19:25
  3 +from __future__ import unicode_literals
  4 +
  5 +from django.db import migrations, models
  6 +
  7 +
  8 +class Migration(migrations.Migration):
  9 +
  10 + dependencies = [
  11 + ('mural', '0002_muralvisualizations'),
  12 + ]
  13 +
  14 + operations = [
  15 + migrations.AlterField(
  16 + model_name='mural',
  17 + name='action',
  18 + field=models.CharField(choices=[('comment', 'Comment'), ('help', 'Ask for Help')], max_length=100, verbose_name='Action'),
  19 + ),
  20 + ]
... ...
mural/models.py
... ... @@ -16,7 +16,7 @@ def validate_img_extension(value):
16 16 raise ValidationError(_('File not supported.'))
17 17  
18 18 class Mural(KnowsChild):
19   - action = models.CharField(_('Action'), max_length = 100, choices = (("comment", _("Comment")), ("help", _("Ask for Help"))), blank = True)
  19 + action = models.CharField(_('Action'), max_length = 100, default = "comment", choices = (("comment", _("Comment")), ("help", _("Ask for Help"))))
20 20 post = models.TextField(_('Post'), blank = True)
21 21 image = models.ImageField(verbose_name = _('Image'), null=True, blank = True, upload_to = 'posts/', validators = [validate_img_extension])
22 22 user = models.ForeignKey(User, verbose_name = _('User'), related_name = "post_user", null = True)
... ...
mural/templates/mural/_form.html 0 → 100644
... ... @@ -0,0 +1,142 @@
  1 +{% load static i18n %}
  2 +{% load widget_tweaks %}
  3 +
  4 +<div class="modal-dialog" role="document">
  5 + <div class="modal-content">
  6 + <div class="modal-body">
  7 + <form id="post-form" method="post" action="{{ form_url }}" enctype="multipart/form-data">
  8 + {% csrf_token %}
  9 + <div class="row">
  10 + <div class="form-group{% if form.has_error %} has-error {% endif %} text-center col-md-6">
  11 + <label for="{{ form.action.0.id_for_label }}" class="text-center post_action">
  12 + <span class="radio">
  13 + <i class="fa fa-commenting-o"></i>
  14 + <br clear="all" />
  15 + {{ form.action.0 }}
  16 + </span>
  17 + </label>
  18 + </div>
  19 + <div class="form-group{% if form.has_error %} has-error {% endif %} text-center col-md-6">
  20 + <label for="{{ form.action.1.id_for_label }}" class="text-center post_action">
  21 + <span class="radio">
  22 + <i class="fa fa-comments-o"></i>
  23 + <br clear="all" />
  24 + {{ form.action.1 }}
  25 + </span>
  26 + </label>
  27 + </div>
  28 + </div>
  29 +
  30 + <div class="form-group{% if form.has_error %} has-error {% endif %}">
  31 + <label for="{{ form.post.auto_id }}">{{ form.post.label }} <span>*</span></label>
  32 + {% render_field form.post class='form-control text_simple_wysiwyg' %}
  33 +
  34 + <span id="helpBlock" class="help-block">{{ form.post.help_text }}</span>
  35 +
  36 + {% if form.post.errors %}
  37 + <div class="alert alert-danger alert-dismissible" role="alert">
  38 + <button type="button" class="close" data-dismiss="alert" aria-label="Close">
  39 + <span aria-hidden="true">&times;</span>
  40 + </button>
  41 + <ul>
  42 + {% for error in form.post.errors %}
  43 + <li>{{ error }}</li>
  44 + {% endfor %}
  45 + </ul>
  46 + </div>
  47 + {% endif %}
  48 + </div>
  49 +
  50 + <div class="form-group{% if form.has_error %} has-error {% endif %} is-fileinput">
  51 + {% render_field form.image %}
  52 +
  53 + <div class="input-group common-file-input">
  54 + <input type="text" readonly="" class="form-control" placeholder="{% trans 'Choose your photo...' %}">
  55 + <span class="input-group-btn input-group-sm">
  56 + <button type="button" class="btn btn-fab btn-fab-mini">
  57 + <i class="material-icons">attach_file</i>
  58 + </button>
  59 + </span>
  60 + </div>
  61 +
  62 + <div class="filedrag">
  63 + {% trans 'Click or drop the file here' %}<br />
  64 +
  65 + <small>{% trans 'The file could not exceed 5MB.' %}</small>
  66 + </div>
  67 +
  68 + <span id="helpBlock" class="help-block">{{ form.image.help_text }}</span>
  69 +
  70 + {% if form.image.errors %}
  71 + <div class="alert alert-danger alert-dismissible" role="alert">
  72 + <button type="button" class="close" data-dismiss="alert" aria-label="Close">
  73 + <span aria-hidden="true">&times;</span>
  74 + </button>
  75 + <ul>
  76 + {% for error in form.image.errors %}
  77 + <li>{{ error }}</li>
  78 + {% endfor %}
  79 + </ul>
  80 + </div>
  81 + {% endif %}
  82 + </div>
  83 + </form>
  84 + </div>
  85 + <div class="modal-footer">
  86 + <div class="col-md-12">
  87 + <button type="submit" id="button" form="post-form" class="btn btn-success btn-raised post-button pull-left">{% trans "Save" %}</button>
  88 + <button type="button" class="btn btn-raised btn-default pull-right" data-dismiss="modal">{% trans "Cancel" %}</button>
  89 + </div>
  90 + </div>
  91 + </div>
  92 +</div>
  93 +
  94 +<script type="text/javascript">
  95 + $(function () {
  96 + $('.text_simple_wysiwyg').summernote({
  97 + dialogsInBody: true,
  98 + height: 150,
  99 + toolbar: [
  100 + // [groupName, [list of button]]
  101 + ['style', ['bold', 'italic']],
  102 + ['insert', ['link']]
  103 + ]
  104 + });
  105 +
  106 + $.material.init();
  107 +
  108 + if (window.File && window.FileList && window.FileReader) {
  109 + Init();
  110 + }
  111 + });
  112 +
  113 + // initialize
  114 + function Init() {
  115 + var small = $("#id_image"),
  116 + filedrag = $(".filedrag"),
  117 + common = $(".common-file-input");
  118 +
  119 + // file select
  120 + small.on("change", FileSelectHandler);
  121 +
  122 + // is XHR2 available?
  123 + var xhr = new XMLHttpRequest();
  124 + if (xhr.upload) {
  125 + // file drop
  126 + filedrag.on("drop", FileSelectHandler);
  127 + filedrag.attr('style', 'display:block');
  128 + common.attr('style', 'display:none');
  129 + }
  130 + }
  131 +
  132 + // file selection
  133 + function FileSelectHandler(e) {
  134 + var files = e.target.files || e.dataTransfer.files,
  135 + parent = $(e.target.offsetParent);
  136 +
  137 + // process all File objects
  138 + for (var i = 0, f; f = files[i]; i++) {
  139 + parent.find('.filedrag').html(f.name);
  140 + }
  141 + }
  142 +</script>
... ...
mural/templates/mural/_view.html 0 → 100644
... ... @@ -0,0 +1,5 @@
  1 +<div class="row panel panel-default">
  2 + <div class="panel-body">
  3 + {{ post.user }}
  4 + </div>
  5 +</div>
0 6 \ No newline at end of file
... ...
mural/templates/mural/list.html
... ... @@ -29,21 +29,72 @@
29 29 </div>
30 30 <div class="col-lg-11 col-md-11 col-sm-11 col-xs-11 post-field">
31 31 <div>
32   - <h4>{% trans 'Wish to make a new post?' %}</h4>
  32 + <h4 data-url="{% url 'mural:create_general' %}">{% trans 'Wish to make a new post?' %}</h4>
33 33 </div>
34 34 </div>
35 35 </div>
36 36 </div>
37 37  
38   - {% if posts.count > 0 %}
39   - {% else %}
40   - <div class="text-center no-subjects">
41   - <i class="fa fa-list"></i>
42   - <h4>{% trans 'There are no posts in this mural yet.' %}</h4>
43   - </div>
44   - {% endif %}
  38 + <div class="posts">
  39 + {% for post in posts %}
  40 + {% include 'mural/_view.html' %}
  41 + {% endfor %}
  42 + </div>
  43 + <div class="text-center no-subjects" {% if posts.count > 0 %} style="display:none" {% endif %}>
  44 + <i class="fa fa-list"></i>
  45 + <h4>{% trans 'There are no posts in this mural yet.' %}</h4>
  46 + </div>
45 47 </div>
46 48 <div class="col-md-3 col-sm-3 col-xs-3">
47 49 </div>
48 50 </div>
  51 +
  52 + <div class="modal fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel"></div>
  53 +
  54 + <script type="text/javascript">
  55 + $(function () {
  56 + $(".post-field").click(function () {
  57 + var url = $(this).find('h4').data('url');
  58 +
  59 + $.ajax({
  60 + url: url,
  61 + success: function (data) {
  62 + $('.modal').html(data);
  63 +
  64 + setPostFormSubmit();
  65 +
  66 + $('.modal').modal('show');
  67 + }
  68 + })
  69 + });
  70 + });
  71 +
  72 + function setPostFormSubmit() {
  73 + var frm = $('#post-form');
  74 +
  75 + frm.submit(function () {
  76 + $.ajax({
  77 + type: frm.attr('method'),
  78 + url: frm.attr('action'),
  79 + data: frm.serialize(),
  80 + dataType: "json",
  81 + success: function (data) {
  82 + $('.posts').prepend(data.view);
  83 +
  84 + $('.no-subjects').attr('style', 'display:none');
  85 +
  86 + $('.modal').modal('hide');
  87 +
  88 + alertify.success(data.message);
  89 + },
  90 + error: function(data) {
  91 + $(".modal").html(data.responseText);
  92 + setPostFormSubmit();
  93 + }
  94 + });
  95 +
  96 + return false;
  97 + });
  98 + }
  99 + </script>
49 100 {% endblock %}
50 101 \ No newline at end of file
... ...
mural/urls.py
... ... @@ -3,4 +3,6 @@ from . import views
3 3  
4 4 urlpatterns = [
5 5 url(r'^$', views.GeneralIndex.as_view(), name='manage_general'),
  6 + url(r'^create_gen/$', views.GeneralCreate.as_view(), name='create_general'),
  7 + url(r'^render_post/([\w_-]+)/$', views.render_gen_post, name='render_post_general'),
6 8 ]
7 9 \ No newline at end of file
... ...
mural/views.py
... ... @@ -2,12 +2,16 @@ from django.shortcuts import get_object_or_404, redirect, render
2 2 from django.views import generic
3 3 from django.contrib import messages
4 4 from django.http import JsonResponse
  5 +from django.template.loader import render_to_string
5 6 from django.core.urlresolvers import reverse, reverse_lazy
6 7 from django.utils.translation import ugettext_lazy as _
7 8 from django.contrib.auth.mixins import LoginRequiredMixin
8 9 from django.db.models import Q, Count
9 10  
  11 +from users.models import User
  12 +
10 13 from .models import GeneralPost, CategoryPost, SubjectPost, MuralVisualizations
  14 +from .forms import GeneralPostForm
11 15  
12 16 class GeneralIndex(LoginRequiredMixin, generic.ListView):
13 17 login_url = reverse_lazy("users:login")
... ... @@ -39,3 +43,53 @@ class GeneralIndex(LoginRequiredMixin, generic.ListView):
39 43 context['mural_menu_active'] = 'subjects_menu_active'
40 44  
41 45 return context
  46 +
  47 +class GeneralCreate(LoginRequiredMixin, generic.edit.CreateView):
  48 + login_url = reverse_lazy("users:login")
  49 + redirect_field_name = 'next'
  50 +
  51 + template_name = 'mural/_form.html'
  52 + form_class = GeneralPostForm
  53 +
  54 + def form_invalid(self, form):
  55 + context = super(GeneralCreate, self).form_invalid(form)
  56 + context.status_code = 400
  57 +
  58 + return context
  59 +
  60 + def form_valid(self, form):
  61 + self.object = form.save(commit = False)
  62 +
  63 + self.object.user = self.request.user
  64 +
  65 + self.object.save()
  66 +
  67 + users = User.objects.all().exclude(id = self.request.user.id)
  68 + entries = []
  69 +
  70 + for user in users:
  71 + entries.append(MuralVisualizations(viewed = False, user = user, post = self.object))
  72 +
  73 + MuralVisualizations.objects.bulk_create(entries)
  74 +
  75 + return super(GeneralCreate, self).form_valid(form)
  76 +
  77 + def get_context_data(self, *args, **kwargs):
  78 + context = super(GeneralCreate, self).get_context_data(*args, **kwargs)
  79 +
  80 + context['form_url'] = reverse_lazy("mural:create_general")
  81 +
  82 + return context
  83 +
  84 + def get_success_url(self):
  85 + return reverse_lazy('mural:render_post_general', args = (self.object.id, ))
  86 +
  87 +def render_gen_post(request, post):
  88 + post = get_object_or_404(GeneralPost, id = post)
  89 +
  90 + context = {}
  91 + context['post'] = post
  92 +
  93 + html = render_to_string("mural/_view.html", context, request)
  94 +
  95 + return JsonResponse({'message': _('Your post was published successfully!'), 'view': html})
... ...