fmartingr
/
shelfzilla
Archived
1
0
Fork 0

Added form to submit volume suggestions

This commit is contained in:
Felipe Martín 2015-05-05 23:31:44 +02:00
parent c9f85efdf0
commit e23c949c22
11 changed files with 410 additions and 63 deletions

View File

@ -20,6 +20,7 @@
"jquery-pjax": "~1.8.1",
"nprogress": "~0.1.3",
"toastr": "~2.0.1",
"imagesloaded": "~3.1.4"
"imagesloaded": "~3.1.4",
"select2": "~4.0.0"
}
}

View File

@ -0,0 +1,82 @@
# coding: utf-8
# from https://bitbucket.org/kmike/django-widget-tweaks/
# django
from django.template import Library
register = Library()
def silence_without_field(fn):
def wrapped(field, attr):
if not field:
return ""
return fn(field, attr)
return wrapped
def _process_field_attributes(field, attr, process):
# split attribute name and value from 'attr:value' string
params = attr.split(':', 1)
attribute = params[0]
value = params[1] if len(params) == 2 else ''
# decorate field.as_widget method with updated attributes
old_as_widget = field.as_widget
def as_widget(self, widget=None, attrs=None, only_initial=False):
attrs = attrs or {}
process(widget or self.field.widget, attrs, attribute, value)
return old_as_widget(widget, attrs, only_initial)
bound_method = type(old_as_widget)
try:
field.as_widget = bound_method(as_widget, field, field.__class__)
except TypeError: # python 3
field.as_widget = bound_method(as_widget, field)
return field
@register.filter("attr")
@silence_without_field
def set_attr(field, attr):
def process(widget, attrs, attribute, value):
attrs[attribute] = value
return _process_field_attributes(field, attr, process)
@register.filter("add_error_attr")
@silence_without_field
def add_error_attr(field, attr):
if hasattr(field, 'errors') and field.errors:
return set_attr(field, attr)
return field
@register.filter("append_attr")
@silence_without_field
def append_attr(field, attr):
def process(widget, attrs, attribute, value):
if attrs.get(attribute):
attrs[attribute] += ' ' + value
elif widget.attrs.get(attribute):
attrs[attribute] = widget.attrs[attribute] + ' ' + value
else:
attrs[attribute] = value
return _process_field_attributes(field, attr, process)
@register.filter("add_class")
@silence_without_field
def add_class(field, css_class):
return append_attr(field, 'class:' + css_class)
@register.filter("add_error_class")
@silence_without_field
def add_error_class(field, css_class):
if hasattr(field, 'errors') and field.errors:
return add_class(field, css_class)
return field

View File

@ -171,7 +171,7 @@ class VolumeAdmin(ImportExportModelAdmin, reversion.VersionAdmin):
}),
(None, {
'classes': ('suit-tab suit-tab-review',),
'fields': ('for_review', 'for_review_comment')
'fields': ('for_review', 'added_by', 'for_review_comment')
}),
(None, {
'classes': ('suit-tab suit-tab-advanced',),

View File

@ -0,0 +1,27 @@
# coding: utf-8
# django
from django import forms
from django.utils.translation import ugettext as _
# app
from . import models
class SuggestVolumeForm(forms.ModelForm):
"""
Form used by users to add a volume that we don't have.
"""
class Meta:
model = models.Volume
fields = (
'number', 'name',
'publisher',
'language',
'pages',
'retail_price',
'isbn_10', 'isbn_13', )
help_texts = {
'number': _("The number of this volume."),
'name': _("Volumes without a number usually have a name instead."),
}

View File

@ -1,6 +1,8 @@
from django.conf.urls import patterns, url
from ..views.series import SeriesListView, SeriesDetailView
from ..views.series import (
SeriesListView, SeriesDetailView, SeriesSuggestVolumeView
)
urlpatterns = patterns(
'',
@ -13,4 +15,8 @@ urlpatterns = patterns(
r'^(?P<sid>\d+)/(?P<slug>[\w-]+)/$',
SeriesDetailView.as_view(),
name='series.detail'),
url(
r'^(?P<sid>\d+)/(?P<slug>[\w-]+)/suggest/$',
SeriesSuggestVolumeView.as_view(),
name='series.suggest-volume'),
)

View File

@ -5,11 +5,20 @@ from django.utils.translation import ugettext as _
from shelfzilla.views import View
from ..models import Series
from .. import forms
class SeriesView(View):
section = 'series'
def get_object(self, sid, slug=None):
if slug:
item = get_object_or_404(Series, pk=sid, slug=slug)
else:
item = get_object_or_404(Series, pk=sid)
return item
class SeriesListView(SeriesView):
template = 'manga/series/list.html'
@ -46,14 +55,16 @@ class SeriesDetailView(SeriesView):
filters = ('language', 'publisher', 'collection')
def get(self, request, sid, slug=None):
vol_filters = {}
vol_filters = {
'for_review': False,
'hidden': False,
}
for search_filter in self.filters:
if search_filter in request.POST and request.POST[search_filter] != "0":
vol_filters['{}_id'.format(search_filter)] = \
int(request.POST[search_filter])
print(vol_filters)
# TODO use self.get_object()
if slug:
item = get_object_or_404(Series, pk=sid, slug=slug)
else:
@ -70,3 +81,40 @@ class SeriesDetailView(SeriesView):
def post(self, request, sid, slug=None):
return self.get(request, sid, slug)
class SeriesSuggestVolumeView(SeriesView):
template = 'manga/series/suggest_volume.html'
form = forms.SuggestVolumeForm
def get(self, request, sid, slug=None):
item = self.get_object(sid, slug)
context = {
'item': item,
'form': self.form(),
}
ctx = RequestContext(request, self.get_context(context))
return render_to_response(self.template, context_instance=ctx)
def post(self, request, sid, slug=None):
item = self.get_object(sid, slug)
form = self.form(self.request.POST)
context = {
'item': item,
}
if form.is_valid():
obj = form.save(commit=False)
obj.added_by = request.user
obj.series = item
obj.for_review = True
obj.save()
context['success'] = True
else:
context['form'] = form
ctx = RequestContext(request, self.get_context(context))
return render_to_response(self.template, context_instance=ctx)

View File

@ -8,8 +8,8 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-01-26 14:45+0100\n"
"PO-Revision-Date: 2015-01-26 14:45+0100\n"
"POT-Creation-Date: 2015-05-05 23:25+0200\n"
"PO-Revision-Date: 2015-05-05 23:26+0200\n"
"Last-Translator: <admin@admin.com>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
@ -32,10 +32,9 @@ msgid "Volume not found."
msgstr "Volumen no encontrado."
#: apps/account/admin.py:85
#, fuzzy
#| msgid "Person"
msgid "Personal info"
msgstr "Persona"
msgstr "Información personal"
#: apps/account/admin.py:87
msgid "Permissions"
@ -167,13 +166,13 @@ msgstr "Sesión finalizada."
msgid "Password changed."
msgstr "Contraseña cambiada."
#: apps/account/views.py:165
#: apps/account/views.py:170
msgid "Welcome to the community! :)"
msgstr "¡Bienvenido a la comunidad! :)"
#: apps/blog/admin.py:24 apps/manga/admin.py:61 apps/manga/admin.py:109
#: apps/manga/admin.py:154 apps/manga/admin.py:202 apps/manga/admin.py:229
#: apps/manga/admin.py:254
#: apps/blog/admin.py:24 apps/manga/admin.py:61 apps/manga/admin.py:111
#: apps/manga/admin.py:158 apps/manga/admin.py:207 apps/manga/admin.py:234
#: apps/manga/admin.py:259
msgid "General"
msgstr "General"
@ -193,6 +192,24 @@ msgstr "Configuración del sitio"
msgid "Social Configuration"
msgstr "Configuración social"
#: apps/faq/models.py:13
msgid "Category"
msgstr "Categoría"
#: apps/faq/models.py:14
#| msgid "Series"
msgid "Categories"
msgstr "Categorías"
#: apps/faq/models.py:35
msgid "Question"
msgstr "Pregunta"
#: apps/faq/models.py:36
#| msgid "Collections"
msgid "Questions"
msgstr "Preguntas"
#: apps/mailing/emails.py:10
msgid "Bienvenido a Shelfzilla"
msgstr ""
@ -205,44 +222,65 @@ msgstr "Marcar items para revisión"
msgid "Items unmarked for review"
msgstr "Desmarcar items para revisión"
#: apps/manga/admin.py:62 apps/manga/admin.py:111 apps/manga/admin.py:156
#: apps/manga/admin.py:203 apps/manga/admin.py:255
#: apps/manga/admin.py:62 apps/manga/admin.py:115 apps/manga/admin.py:160
#: apps/manga/admin.py:208 apps/manga/admin.py:260
msgid "Review"
msgstr "Para revisión"
#: apps/manga/admin.py:63 apps/manga/admin.py:112 apps/manga/admin.py:157
#: apps/manga/admin.py:204 apps/manga/admin.py:256
#: apps/manga/admin.py:63 apps/manga/admin.py:116 apps/manga/admin.py:161
#: apps/manga/admin.py:209 apps/manga/admin.py:261
msgid "Advanced"
msgstr "Avanzado"
#: apps/manga/admin.py:83 apps/manga/models.py:134 apps/manga/models.py:135
#: themes/bootflat/templates/_layout.html:39
#: themes/bootflat/templates/_layout.html:42
#: themes/bootflat/templates/homepage/home.html:72
#: themes/bootflat/templates/manga/publishers/detail.html:19
#: themes/bootflat/templates/manga/series/list.html:4
msgid "Series"
msgstr "Series"
#: apps/manga/admin.py:110 apps/manga/admin.py:137 apps/manga/models.py:200
#: apps/manga/admin.py:112 apps/manga/models.py:54
#: themes/bootflat/templates/_layout.html:45
#: themes/bootflat/templates/manga/publishers/list.html:4
#: themes/bootflat/templates/manga/series/detail.html:58
#: themes/bootflat/templates/manga/series/suggest_volume.html:49
msgid "Publishers"
msgstr "Editoriales"
#: apps/manga/admin.py:113 apps/manga/admin.py:141 apps/manga/models.py:200
#: themes/bootflat/templates/homepage/home.html:75
#: themes/bootflat/templates/manga/publishers/detail.html:22
msgid "Volumes"
msgstr "Volúmenes"
#: apps/manga/admin.py:155
#: apps/manga/admin.py:114 apps/manga/models.py:68 apps/manga/models.py:141
#: themes/bootflat/templates/users/profile.html:27
msgid "Summary"
msgstr "Resumen"
#: apps/manga/admin.py:159
msgid "Cover"
msgstr "Carátula"
#: apps/manga/admin.py:194
#: apps/manga/admin.py:198
#: themes/bootflat/templates/_admin/volumes/change_series.html:4
#: themes/bootflat/templates/_admin/volumes/change_series.html:8
msgid "Change volume series"
msgstr "Cambiar serie de los volúmenes"
#: apps/manga/admin.py:243
#: apps/manga/admin.py:248
msgid "Flag"
msgstr "Bandera"
#: apps/manga/forms.py:25
msgid "The number of this volume."
msgstr "El número de este tomo."
#: apps/manga/forms.py:26
msgid "Volumes without a number usually have a name instead."
msgstr "Los tomos que no tienen número normalmente tienen un nombre especial."
#: apps/manga/models.py:15 apps/manga/models.py:65 apps/manga/models.py:172
#: apps/manga/models.py:204 apps/manga/models.py:218 apps/manga/models.py:231
msgid "Name"
@ -257,16 +295,10 @@ msgid "URL"
msgstr "URL"
#: apps/manga/models.py:53
#: themes/bootflat/templates/manga/series/detail.html:120
#: themes/bootflat/templates/manga/series/detail.html:123
msgid "Publisher"
msgstr "Editorial"
#: apps/manga/models.py:54 themes/bootflat/templates/_layout.html:42
#: themes/bootflat/templates/manga/publishers/list.html:4
#: themes/bootflat/templates/manga/series/detail.html:55
msgid "Publishers"
msgstr "Editoriales"
#: apps/manga/models.py:59
msgid "Open"
msgstr "Abierta"
@ -283,11 +315,6 @@ msgstr "Cancelada"
msgid "On-hold"
msgstr "Parada"
#: apps/manga/models.py:68 apps/manga/models.py:141
#: themes/bootflat/templates/users/profile.html:27
msgid "Summary"
msgstr "Resumen"
#: apps/manga/models.py:70 apps/manga/models.py:150
msgid "Status"
msgstr "Estado"
@ -321,6 +348,7 @@ msgid "Release date"
msgstr "Fecha de lanzamiento"
#: apps/manga/models.py:199
#: themes/bootflat/templates/_admin/manga/series/includes/volumes.html:4
msgid "Volume"
msgstr "Volumen"
@ -329,7 +357,7 @@ msgid "Default"
msgstr "Por defecto"
#: apps/manga/models.py:213
#: themes/bootflat/templates/manga/series/detail.html:134
#: themes/bootflat/templates/manga/series/detail.html:137
#: themes/bootflat/templates/users/profile.html:30
#: themes/bootflat/templates/users/profile/collection.html:4
msgid "Collection"
@ -348,7 +376,7 @@ msgid "Persons"
msgstr "Personas"
#: apps/manga/models.py:239
#: themes/bootflat/templates/manga/series/detail.html:106
#: themes/bootflat/templates/manga/series/detail.html:109
msgid "Language"
msgstr "Idioma"
@ -390,7 +418,7 @@ msgstr "ha leído"
#: apps/manga/views/search.py:11 apps/manga/views/search.py:13
#: themes/bootflat/templates/_admin/volumes/includes/cover.html:6
#: themes/bootflat/templates/_admin/volumes/includes/cover.html:15
#: themes/bootflat/templates/_layout.html:83
#: themes/bootflat/templates/_layout.html:91
msgid "Search"
msgstr "Buscar"
@ -422,19 +450,19 @@ msgstr "{} marcado como no leído"
msgid "{} marked as read!"
msgstr "¡{} marcado como leído!"
#: models.py:7
#: models.py:11
msgid "For review"
msgstr "Para revisión"
#: models.py:9
#: models.py:15
msgid "Review comment"
msgstr "Comentario de revisión"
#: models.py:11
#: models.py:17
msgid "Hidden"
msgstr "Oculto"
#: settings/base.py:131
#: settings/base.py:139
msgid "Spanish"
msgstr "Español"
@ -454,7 +482,11 @@ msgstr ""
"Hubo un error interno del servidor. Puede ser temporal, pero si el problema "
"persiste, contacta con nosotros."
#: themes/bootflat/templates/_admin/manga/series/includes/volumes.html:13
#: themes/bootflat/templates/_admin/manga/series/includes/volumes.html:4
msgid "Add"
msgstr "Añadir"
#: themes/bootflat/templates/_admin/manga/series/includes/volumes.html:18
msgid "Edit"
msgstr "Editar"
@ -479,40 +511,43 @@ msgstr "Carátula actual:"
msgid "Update with this"
msgstr "Actualizar con esta"
#: themes/bootflat/templates/_layout.html:27
#: themes/bootflat/templates/_layout.html:30
msgid "Toggle navigation"
msgstr "Mostrar/Ocultar navegación"
#: themes/bootflat/templates/_layout.html:47
#: themes/bootflat/templates/_layout.html:49
msgid "Faq"
msgstr "FAQ"
#: themes/bootflat/templates/_layout.html:55
#: themes/bootflat/templates/_layout.html:63
#: themes/bootflat/templates/users/profile-pjax.html:4
#: themes/bootflat/templates/users/profile.html:4
msgid "Profile"
msgstr "Perfil"
#: themes/bootflat/templates/_layout.html:60
#: themes/bootflat/templates/_layout.html:68
msgid "Logout"
msgstr "Cerrar sesión"
#: themes/bootflat/templates/_layout.html:67
#: themes/bootflat/templates/_layout.html:75
#: themes/bootflat/templates/account/register.html:15
#: themes/bootflat/templates/account/register.html:46
msgid "Register"
msgstr "Registrarse"
#: themes/bootflat/templates/_layout.html:72
#: themes/bootflat/templates/_layout.html:80
msgid "Log in"
msgstr "Entrar"
#: themes/bootflat/templates/account/_layout.html:4
msgid "Account"
msgstr ""
msgstr "Cuenta"
#: themes/bootflat/templates/account/main.html:31
#, fuzzy
#| msgid "Change to: "
msgid "Change password"
msgstr "Cambiar a:"
msgstr "Cambiar contraseña"
#: themes/bootflat/templates/homepage/home.html:10
msgid "Upcoming volumes"
@ -541,7 +576,7 @@ msgstr "Usuarios"
#: themes/bootflat/templates/manga/publishers/detail.html:10
#: themes/bootflat/templates/manga/series/detail.html:10
#: themes/bootflat/templates/manga/series/includes/volume.html:52
#: themes/bootflat/templates/manga/series/includes/volume.html:57
msgid "Edit in admin"
msgstr "Editar en el admin"
@ -559,33 +594,37 @@ msgstr "Buscando..."
msgid "No results"
msgstr "Sin resultados"
#: themes/bootflat/templates/manga/series/detail.html:26
#: themes/bootflat/templates/manga/series/detail.html:29
#: themes/bootflat/templates/manga/series/suggest_volume.html:20
msgid "Art"
msgstr "Arte"
#: themes/bootflat/templates/manga/series/detail.html:41
#: themes/bootflat/templates/manga/series/detail.html:44
#: themes/bootflat/templates/manga/series/suggest_volume.html:35
msgid "Story"
msgstr "Historia"
#: themes/bootflat/templates/manga/series/detail.html:60
#: themes/bootflat/templates/manga/series/detail.html:63
#: themes/bootflat/templates/manga/series/suggest_volume.html:54
msgid "Original publisher"
msgstr "Editorial original"
#: themes/bootflat/templates/manga/series/detail.html:74
#: themes/bootflat/templates/manga/series/detail.html:77
#: themes/bootflat/templates/manga/series/suggest_volume.html:68
msgid "More info"
msgstr "Más información"
#: themes/bootflat/templates/manga/series/detail.html:108
#: themes/bootflat/templates/manga/series/detail.html:122
#: themes/bootflat/templates/manga/series/detail.html:136
#: themes/bootflat/templates/manga/series/detail.html:111
#: themes/bootflat/templates/manga/series/detail.html:125
#: themes/bootflat/templates/manga/series/detail.html:139
msgid "All"
msgstr "Todos"
#: themes/bootflat/templates/manga/series/detail.html:146
#: themes/bootflat/templates/manga/series/detail.html:149
msgid "Filter"
msgstr "Filtrar"
#: themes/bootflat/templates/manga/series/includes/volume.html:44
#: themes/bootflat/templates/manga/series/includes/volume.html:49
#, python-format
msgid "%(pages)s pages"
msgstr "%(pages)s páginas"
@ -594,6 +633,11 @@ msgstr "%(pages)s páginas"
msgid "other"
msgstr "otros"
#: themes/bootflat/templates/manga/series/suggest_volume.html:106
#| msgid "For review"
msgid "Submit for review"
msgstr "Enviar para revisión"
#: themes/bootflat/templates/users/login.html:27
msgid "Access the site"
msgstr "Accede al sitio"

View File

@ -5,12 +5,15 @@
{% block main_content %}
<div class="container">
{% if USER_IS_STAFF and USER_CONFIG.show_admin_links %}
<div class="text-right">
{% if USER_IS_STAFF and USER_CONFIG.show_admin_links %}
<a class="btn btn-info" href="{% url 'admin:manga_series_change' item.pk %}">{% trans "Edit in admin" %}</a>
{% endif %}
{% if user.is_authenticated %}
<p>¿No encuentras el tomo que tienes? <a class="btn btn-info" href="{% url 'series.suggest-volume' item.pk item.slug %}">Añádelo a Shelfzila</a></p>
{% endif %}
</div>
<br />
{% endif %}
<div class="row">
<div class="col-md-3">
<div class="panel panel-warning">

View File

@ -0,0 +1,136 @@
{% extends '_layout.html'|pjax:request %}
{% load i18n staticfiles field_tags %}
{% block page_title %}{{ block.super }} | {{ item.name }}{% endblock %}
{% block javascript %}
{{ block.super }}
<script type="text/javascript" src="{% static "bower/select2/dist/js/select2.js" %}"></script>
<script type="text/javascript">
$(function() {
$('select').select2();
});
</script>
{% endblock %}
{% block stylesheets %}
{{ block.super }}
<link rel="stylesheet" href="{% static "bower/select2/dist/css/select2.css" %}" media="screen" title="no title" charset="utf-8">
{% endblock %}
{% block main_content %}
<div class="container">
<div class="row">
<div class="col-md-3">
<div class="panel panel-warning">
{% if item.last_volume_cover %}
<div class="panel-body text-center">
<img src="{{ item.last_volume_cover.url }}" class="max-width-80" />
</div>
{% endif %}
</div>
{% if item.art.count %}
<div class="panel panel-default">
<div class="panel-heading">
<h2 class="panel-title text-center">{% trans "Art" %}</h2>
</div>
<ul class="list-group">
{% for person in item.art.all %}
<li class="list-group-item">
{{ person.name }}
</li>
{% endfor %}
</ul>
</div>
{% endif %}
{% if item.story.count %}
<div class="panel panel-default">
<div class="panel-heading">
<h2 class="panel-title text-center">{% trans "Story" %}</h2>
</div>
<ul class="list-group">
{% for person in item.story.all %}
<li class="list-group-item">
{{ person.name }}
</li>
{% endfor %}
</ul>
</div>
{% endif %}
<div class="panel panel-default">
<div class="panel-heading">
<h2 class="panel-title text-center">{% trans "Publishers" %}</h2>
</div>
<ul class="list-group">
{% if item.original_publisher %}
<li class="list-group-item">
<strong>{% trans "Original publisher" %}:</strong>
{% comment %}
<a href="{{ publisher.get_absolute_url }}" data-pajax>{{ item.original_publisher.name }}</a>
{% endcomment %}
<span class="pull-right"><i>{{ item.original_publisher.name }}</i></span>
</li>
{% endif %}
{% if item.publishers.count > 0 %}
{% for publisher in item.publishers.all %}
<li class="list-group-item">
<h4 class="list-group-item-heading">{{ publisher.publisher.name }}</h4>
<!--<span class="badge badge-default">{{ publisher.volumes.count }}</span> -->
<span class="badge badge-{{ publisher.get_status_display_class }}">{{ publisher.get_status_display }}</span>
<div><a href="{{ publisher.publisher.get_absolute_url }}" data-pajax>{% trans "More info" %} &raquo;</a></div>
</li>
{% endfor %}
{% endif %}
</ul>
</div>
</div>
<div class="col-md-9">
<div class="panel panel-primary">
<div class="panel-heading">
<h1 class="panel-title panel-title-alt text-center">{{ item.name }}</h1>
</div>
</div>
{% if not success %}
<div>
<div class="alert alert-info">
<p>¡Oooops! ¡Parece que hay un tomo que tú tienes y nosotros no tenemos registrado!</p>
<p>Nos harías un gran favor si introduces la información que poseas de dicho tomo aquí para así poder
ayudar a otras personas de la comunidad.</p>
</div>
<div class="well">
<form method="post" class="form">
{% csrf_token %}
{% for field in form %}
{% for error in field.errors %}
<p><span class="label label-danger">{{ error|striptags }}</span></p>
{% endfor %}
<div class="form-group {% if field.errors %}has-error has-feedback{% endif %}">
<label class="control-label">{{ field.label }}</label>
{{ field|add_class:'form-control' }}
{% if field.errors %}
<span class="glyphicon glyphicon-remove form-control-feedback"></span>
{% endif %}
</div>
{% endfor %}
<div class="text-center">
<button class="btn btn-primary" type="submit">{% trans "Submit for review" %}</button>
</div>
</form>
</div>
</div>
{% else %}
<div class="alert alert-success text-center">
<h4>¡Muchas gracias por colaborar con Shelfzilla!</h4>
<p>Tu tomo será revisado por nuestro staff para comprobar que los datos son correctos y una vez
sea aceptado aparecerá en la web, y como es natural, ¡en tu colección!</p>
<a class="btn btn-success" href="{% url 'series.detail' item.pk item.slug %}">Volver a {{ item.name }}</a>
</div>
{% endif %}
</div>
</div>
</div>
{% endblock %}