ups
This commit is contained in:
commit
67a9f0f382
|
@ -1,5 +1,5 @@
|
||||||
shelfzilla
|
shelfzilla
|
||||||
==========
|
===========
|
||||||
|
|
||||||
## Prepare environment for local development
|
## Prepare environment for local development
|
||||||
|
|
||||||
|
@ -21,3 +21,4 @@ fab runserver
|
||||||
- grunt-cli installed as global resource
|
- grunt-cli installed as global resource
|
||||||
- bower installed as a global resource
|
- bower installed as a global resource
|
||||||
|
|
||||||
|
Enjoy!
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
-r ../requirements.txt
|
-r ../requirements.txt
|
||||||
gunicorn==18.0
|
gunicorn==18.0
|
||||||
toml==0.8.2
|
toml==0.9.0
|
||||||
|
opbeat==2.1
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Base
|
# Base
|
||||||
Django==1.7.1
|
Django==1.7.2
|
||||||
|
|
||||||
# Admin
|
# Admin
|
||||||
django-suit==0.2.11
|
django-suit==0.2.11
|
||||||
|
@ -9,6 +9,9 @@ django-import-export==0.2.6
|
||||||
|
|
||||||
# Fixes
|
# Fixes
|
||||||
|
|
||||||
|
# Mailing
|
||||||
|
django-mailgun==0.2.2
|
||||||
|
|
||||||
# Statics
|
# Statics
|
||||||
django-compressor==1.4
|
django-compressor==1.4
|
||||||
|
|
||||||
|
@ -17,7 +20,13 @@ dj-database-url==0.3.0
|
||||||
psycopg2==2.5.4
|
psycopg2==2.5.4
|
||||||
|
|
||||||
# Files
|
# Files
|
||||||
|
django-mptt==0.6.1
|
||||||
django-filer==0.9.8
|
django-filer==0.9.8
|
||||||
|
|
||||||
# Blog
|
# Blog
|
||||||
django-ckeditor-updated==4.4.4
|
django-ckeditor-updated==4.4.4
|
||||||
|
|
||||||
|
# API
|
||||||
|
djoser==0.2.1
|
||||||
|
djangorestframework==3.1.1
|
||||||
|
django-cors-headers==1.0.0
|
||||||
|
|
|
@ -54,7 +54,7 @@ def setup_virtualenv():
|
||||||
Creates or updates a virtualenv
|
Creates or updates a virtualenv
|
||||||
"""
|
"""
|
||||||
print(yellow('Create virtualenv'))
|
print(yellow('Create virtualenv'))
|
||||||
local('virtualenv-2.7 .virtualenv')
|
local('virtualenv .virtualenv')
|
||||||
|
|
||||||
with virtualenv():
|
with virtualenv():
|
||||||
print(yellow('Installing requirements'))
|
print(yellow('Installing requirements'))
|
||||||
|
|
|
@ -29,7 +29,7 @@ function validations() {
|
||||||
PID_PATH=/var/run/shelfzilla
|
PID_PATH=/var/run/shelfzilla
|
||||||
PID_FILE=${PID_PATH}/${INSTANCE}.pid
|
PID_FILE=${PID_PATH}/${INSTANCE}.pid
|
||||||
P_USER="shelfzilla"
|
P_USER="shelfzilla"
|
||||||
LOG_PATH=/var/log/shefzilla
|
LOG_PATH=/var/log/shelfzilla
|
||||||
LOG_FILE=shelfzilla.log
|
LOG_FILE=shelfzilla.log
|
||||||
FCGI_PORT=8000
|
FCGI_PORT=8000
|
||||||
FCGI_IP=127.0.0.1
|
FCGI_IP=127.0.0.1
|
||||||
|
|
|
@ -61,20 +61,20 @@ cp -r %{_gitdir}/rpm/scripts/shelfzilla $RPM_BUILD_ROOT%{_app_dir}/init/
|
||||||
#rmdir %{_app_dir}/init/
|
#rmdir %{_app_dir}/init/
|
||||||
|
|
||||||
## Npm install
|
## Npm install
|
||||||
#cd %{_app_dir} && npm install --production
|
cd %{_app_dir} && npm install --production
|
||||||
|
|
||||||
## pip install
|
## pip install
|
||||||
#pip install -r %{_app_dir}/config/production/requirements.txt
|
pip install -r %{_app_dir}/config/production/requirements.txt
|
||||||
|
|
||||||
## Migrate
|
## Migrate
|
||||||
#python2.7 %{_app_dir}/manage.py migrate --no-initial-data
|
python2.7 %{_app_dir}/manage.py migrate --no-initial-data
|
||||||
|
|
||||||
## Bower
|
## Bower
|
||||||
#cd %{_app_dir}
|
cd %{_app_dir}
|
||||||
#bower install --allow-root
|
bower install --allow-root
|
||||||
|
|
||||||
## Collect static
|
## Collect static
|
||||||
#python2.7 manage.py collectstatic --clear --noinput
|
python2.7 manage.py collectstatic --clear --noinput
|
||||||
|
|
||||||
# -------------------------------------------------------------------------------------------- #
|
# -------------------------------------------------------------------------------------------- #
|
||||||
# pre-uninstall section:
|
# pre-uninstall section:
|
||||||
|
@ -101,5 +101,3 @@ rm -rf $RPM_BUILD_ROOT
|
||||||
%{_app_dir}/*
|
%{_app_dir}/*
|
||||||
%{_app_dir}/.bowerrc
|
%{_app_dir}/.bowerrc
|
||||||
%{_init_path}/shelfzilla
|
%{_init_path}/shelfzilla
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -103,3 +103,17 @@ class UserAdmin(DjangoUserAdmin):
|
||||||
# Now register the new UserAdmin...
|
# Now register the new UserAdmin...
|
||||||
admin.site.register(models.User, UserAdmin)
|
admin.site.register(models.User, UserAdmin)
|
||||||
admin.site.register(Permission)
|
admin.site.register(Permission)
|
||||||
|
|
||||||
|
|
||||||
|
class AccessCodeAdmin(admin.ModelAdmin):
|
||||||
|
list_display = ('code', 'max_uses', 'expiration', 'active', 'uses',
|
||||||
|
'usable')
|
||||||
|
|
||||||
|
def uses(self, obj):
|
||||||
|
return obj.uses
|
||||||
|
|
||||||
|
def usable(self, obj):
|
||||||
|
return obj.usable
|
||||||
|
usable.boolean = True
|
||||||
|
|
||||||
|
admin.site.register(models.AccessCode, AccessCodeAdmin)
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
# coding: utf-8
|
||||||
|
|
||||||
|
# django
|
||||||
|
|
||||||
|
# third party
|
||||||
|
from rest_framework import serializers
|
||||||
|
|
||||||
|
# own
|
||||||
|
|
||||||
|
|
||||||
|
class FeedSerializer(serializers.Serializer):
|
||||||
|
pass
|
|
@ -0,0 +1,12 @@
|
||||||
|
# coding: utf-8
|
||||||
|
|
||||||
|
# third
|
||||||
|
from rest_framework.routers import DefaultRouter
|
||||||
|
|
||||||
|
# own
|
||||||
|
from .views import FeedViewSet
|
||||||
|
|
||||||
|
|
||||||
|
router = DefaultRouter(trailing_slash=False)
|
||||||
|
router.register(r'feed', FeedViewSet, base_name='feed')
|
||||||
|
urlpatterns = router.urls
|
|
@ -0,0 +1,43 @@
|
||||||
|
# coding: utf-8
|
||||||
|
|
||||||
|
# python
|
||||||
|
from itertools import chain
|
||||||
|
import json
|
||||||
|
|
||||||
|
# third
|
||||||
|
from rest_framework import viewsets
|
||||||
|
from rest_framework.response import Response
|
||||||
|
from rest_framework.permissions import IsAuthenticated
|
||||||
|
|
||||||
|
# own
|
||||||
|
from shelfzilla.apps.manga.models import (
|
||||||
|
UserReadVolume, UserHaveVolume, UserWishlistVolume
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class FeedViewSet(viewsets.ViewSet):
|
||||||
|
"""
|
||||||
|
"""
|
||||||
|
permission_classes = (IsAuthenticated,)
|
||||||
|
|
||||||
|
def list(self, request):
|
||||||
|
owned_list = UserHaveVolume.objects.filter(user=request.user)
|
||||||
|
wishlisted_list = UserWishlistVolume.objects.filter(user=request.user)
|
||||||
|
read_list = UserReadVolume.objects.filter(user=request.user)
|
||||||
|
|
||||||
|
timeline = sorted(
|
||||||
|
chain(owned_list, wishlisted_list, read_list),
|
||||||
|
key=lambda model: model.date,
|
||||||
|
reverse=True
|
||||||
|
)[:20]
|
||||||
|
|
||||||
|
result = []
|
||||||
|
for item in timeline:
|
||||||
|
event = {
|
||||||
|
'date': item.date,
|
||||||
|
'message': item.timeline_message,
|
||||||
|
'type': item.event_type,
|
||||||
|
}
|
||||||
|
result.append(event)
|
||||||
|
|
||||||
|
return Response(result)
|
|
@ -0,0 +1,15 @@
|
||||||
|
# coding: utf-8
|
||||||
|
|
||||||
|
# py3
|
||||||
|
from __future__ import absolute_import
|
||||||
|
|
||||||
|
# django
|
||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class AccountConfig(AppConfig):
|
||||||
|
name = 'account'
|
||||||
|
verbose_name = "Account"
|
||||||
|
|
||||||
|
def ready(self):
|
||||||
|
from . import signals
|
|
@ -1,10 +1,13 @@
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.contrib.auth import authenticate
|
from django.contrib.auth import authenticate
|
||||||
|
from django.db import transaction
|
||||||
from django.contrib.auth.forms import (
|
from django.contrib.auth.forms import (
|
||||||
PasswordChangeForm as DjangoPasswordChangeForm
|
PasswordChangeForm as DjangoPasswordChangeForm
|
||||||
)
|
)
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
from . import models
|
||||||
|
|
||||||
|
|
||||||
class LoginForm(forms.Form):
|
class LoginForm(forms.Form):
|
||||||
username = forms.CharField(max_length=75, label=_('Username'))
|
username = forms.CharField(max_length=75, label=_('Username'))
|
||||||
|
@ -43,3 +46,51 @@ class LoginForm(forms.Form):
|
||||||
|
|
||||||
class PasswordChangeForm(DjangoPasswordChangeForm):
|
class PasswordChangeForm(DjangoPasswordChangeForm):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class RegistrationForm(forms.ModelForm):
|
||||||
|
"""
|
||||||
|
Custom for for registering an user
|
||||||
|
"""
|
||||||
|
password1 = forms.CharField(label=_('Password'),
|
||||||
|
widget=forms.PasswordInput)
|
||||||
|
password2 = forms.CharField(label=_('Repeat password'),
|
||||||
|
widget=forms.PasswordInput)
|
||||||
|
access_code = forms.CharField(label=_('Invitation code'), required=True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = models.User
|
||||||
|
fields = ('email', 'username', )
|
||||||
|
|
||||||
|
def get_access_code(self):
|
||||||
|
try:
|
||||||
|
return models.AccessCode.objects.get(
|
||||||
|
code=self.cleaned_data['access_code'])
|
||||||
|
except models.AccessCode.DoesNotExist:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def clean_access_code(self):
|
||||||
|
code = self.get_access_code()
|
||||||
|
if not code or (code and not code.usable):
|
||||||
|
raise forms.ValidationError(_('Invitation code is not valid'))
|
||||||
|
|
||||||
|
return self.cleaned_data['access_code']
|
||||||
|
|
||||||
|
def clean_password2(self):
|
||||||
|
# Check that the two password entries match
|
||||||
|
password1 = self.cleaned_data.get("password1")
|
||||||
|
password2 = self.cleaned_data.get("password2")
|
||||||
|
if password1 and password2 and password1 != password2:
|
||||||
|
raise forms.ValidationError("Passwords don't match")
|
||||||
|
return password2
|
||||||
|
|
||||||
|
def save(self, commit=True):
|
||||||
|
# Save the provided password in hashed format
|
||||||
|
with transaction.atomic():
|
||||||
|
user = super(RegistrationForm, self).save(commit=False)
|
||||||
|
access_code = self.get_access_code()
|
||||||
|
user.access_code = access_code
|
||||||
|
user.set_password(self.cleaned_data["password1"])
|
||||||
|
if commit:
|
||||||
|
user.save()
|
||||||
|
return user
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import models, migrations
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('account', '0002_auto_20141111_1208'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='AccessCode',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||||
|
('code', models.CharField(max_length=128, verbose_name='Code')),
|
||||||
|
('max_uses', models.IntegerField(default=1, verbose_name='Number of uses')),
|
||||||
|
('expiration', models.DateTimeField(default=None, null=True, verbose_name='Expires')),
|
||||||
|
('active', models.BooleanField(default=True, verbose_name='Active')),
|
||||||
|
('user', models.ForeignKey(related_name='access_codes', blank=True, to=settings.AUTH_USER_MODEL, null=True)),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Access code',
|
||||||
|
'verbose_name_plural': 'Access codes',
|
||||||
|
},
|
||||||
|
bases=(models.Model,),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='user',
|
||||||
|
name='access_code',
|
||||||
|
field=models.ForeignKey(related_name='used_by', blank=True, to='account.AccessCode', null=True),
|
||||||
|
preserve_default=True,
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,20 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import models, migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('account', '0003_auto_20150110_1056'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='accesscode',
|
||||||
|
name='expiration',
|
||||||
|
field=models.DateTimeField(default=None, null=True, verbose_name='Expires', blank=True),
|
||||||
|
preserve_default=True,
|
||||||
|
),
|
||||||
|
]
|
|
@ -92,6 +92,11 @@ class User(AbstractBaseUser,
|
||||||
USERNAME_FIELD = 'username'
|
USERNAME_FIELD = 'username'
|
||||||
REQUIRED_FIELDS = ('email',)
|
REQUIRED_FIELDS = ('email',)
|
||||||
|
|
||||||
|
# Access codes / Invitations
|
||||||
|
access_code = models.ForeignKey('account.AccessCode',
|
||||||
|
null=True, blank=True,
|
||||||
|
related_name='used_by')
|
||||||
|
|
||||||
objects = UserManager()
|
objects = UserManager()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
@ -132,3 +137,40 @@ class User(AbstractBaseUser,
|
||||||
return today.year - birthdate.year - (
|
return today.year - birthdate.year - (
|
||||||
(today.month, today.day) < (birthdate.month, birthdate_day)
|
(today.month, today.day) < (birthdate.month, birthdate_day)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class AccessCode(models.Model):
|
||||||
|
code = models.CharField(_('Code'), max_length=128)
|
||||||
|
max_uses = models.IntegerField(_('Number of uses'), default=1)
|
||||||
|
user = models.ForeignKey(User, null=True, blank=True,
|
||||||
|
related_name='access_codes')
|
||||||
|
expiration = models.DateTimeField(_('Expires'), null=True, blank=True,
|
||||||
|
default=None)
|
||||||
|
active = models.BooleanField(_('Active'), default=True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = _('Access code')
|
||||||
|
verbose_name_plural = _('Access codes')
|
||||||
|
|
||||||
|
def __unicode__(self):
|
||||||
|
return self.code
|
||||||
|
|
||||||
|
@property
|
||||||
|
def uses(self):
|
||||||
|
return self.used_by.count()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def usable(self):
|
||||||
|
# Check if active
|
||||||
|
if not self.active:
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Check if expired
|
||||||
|
if self.expiration and (timezone.now() >= self.expiration):
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Check if it someone already used it
|
||||||
|
if self.used_by.count() == self.max_uses:
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
# coding: utf-8
|
||||||
|
|
||||||
|
# django
|
||||||
|
from django.dispatch import Signal
|
||||||
|
from django.dispatch import receiver
|
||||||
|
|
||||||
|
|
||||||
|
user_registered = Signal(providing_args=["user"])
|
||||||
|
|
||||||
|
|
||||||
|
@receiver(user_registered)
|
||||||
|
def send_email_new_user(sender, **kwargs):
|
||||||
|
from shelfzilla.apps.mailing.emails import RegistrationEmail
|
||||||
|
mail = RegistrationEmail({"user": kwargs.get('user')})
|
||||||
|
mail.send()
|
|
@ -1,10 +1,13 @@
|
||||||
from django.conf.urls import patterns, url
|
from django.conf.urls import patterns, url
|
||||||
|
|
||||||
from .views import LoginView, LogoutView, UserProfileView, AccountView
|
from .views import (
|
||||||
|
LoginView, LogoutView, UserProfileView, AccountView, RegisterView
|
||||||
|
)
|
||||||
|
|
||||||
urlpatterns = patterns(
|
urlpatterns = patterns(
|
||||||
'',
|
'',
|
||||||
url(r'^login/$', LoginView.as_view(), name="login"),
|
url(r'^login/$', LoginView.as_view(), name="login"),
|
||||||
|
url(r'^register/$', RegisterView.as_view(), name="register"),
|
||||||
url(r'^logout/$', LogoutView.as_view(), name="logout"),
|
url(r'^logout/$', LogoutView.as_view(), name="logout"),
|
||||||
url(
|
url(
|
||||||
r'^user/(?P<username>[\w\d\-\.]+)/$',
|
r'^user/(?P<username>[\w\d\-\.]+)/$',
|
||||||
|
|
|
@ -2,7 +2,7 @@ from itertools import chain
|
||||||
from django.views.generic import View
|
from django.views.generic import View
|
||||||
from django.template import RequestContext
|
from django.template import RequestContext
|
||||||
from django.shortcuts import render_to_response, get_object_or_404
|
from django.shortcuts import render_to_response, get_object_or_404
|
||||||
from django.contrib.auth import logout
|
from django.contrib.auth import logout, authenticate, login
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.utils.decorators import method_decorator
|
from django.utils.decorators import method_decorator
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
|
@ -11,8 +11,9 @@ from django.contrib import messages
|
||||||
from django.contrib.auth import login
|
from django.contrib.auth import login
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
|
|
||||||
from .forms import LoginForm, PasswordChangeForm
|
from .forms import LoginForm, PasswordChangeForm, RegistrationForm
|
||||||
from .models import User
|
from .models import User
|
||||||
|
from .signals import user_registered
|
||||||
from shelfzilla.apps.manga.models import (
|
from shelfzilla.apps.manga.models import (
|
||||||
UserReadVolume, UserHaveVolume, UserWishlistVolume
|
UserReadVolume, UserHaveVolume, UserWishlistVolume
|
||||||
)
|
)
|
||||||
|
@ -140,3 +141,35 @@ class AccountView(View):
|
||||||
|
|
||||||
ctx = RequestContext(request, data)
|
ctx = RequestContext(request, data)
|
||||||
return render_to_response(self.template, context_instance=ctx)
|
return render_to_response(self.template, context_instance=ctx)
|
||||||
|
|
||||||
|
|
||||||
|
class RegisterView(View):
|
||||||
|
template = 'account/register.html'
|
||||||
|
form_class = RegistrationForm
|
||||||
|
|
||||||
|
def get(self, request):
|
||||||
|
form_data = {}
|
||||||
|
|
||||||
|
if 'code' in request.GET:
|
||||||
|
form_data['access_code'] = request.GET['code']
|
||||||
|
|
||||||
|
data = {
|
||||||
|
'form': self.form_class(initial=form_data)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx = RequestContext(request, data)
|
||||||
|
return render_to_response(self.template, context_instance=ctx)
|
||||||
|
|
||||||
|
def post(self, request):
|
||||||
|
form = self.form_class(request.POST)
|
||||||
|
if form.is_valid():
|
||||||
|
form.save()
|
||||||
|
user = authenticate(username=request.POST.get('username'),
|
||||||
|
password=request.POST.get('password1'))
|
||||||
|
login(request, user)
|
||||||
|
messages.success(request, _('Welcome to the community! :)'))
|
||||||
|
user_registered.send(sender=self.__class__, user=user)
|
||||||
|
return HttpResponseRedirect(reverse('homepage'))
|
||||||
|
|
||||||
|
ctx = RequestContext(request, {'form': form})
|
||||||
|
return render_to_response(self.template, context_instance=ctx)
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
# coding: utf-8
|
||||||
|
|
||||||
|
# django
|
||||||
|
from django.contrib import admin
|
||||||
|
|
||||||
|
# app
|
||||||
|
from .models import QuestionAnswerCategory, QuestionAnswer
|
||||||
|
|
||||||
|
|
||||||
|
class QuestionAnswerInline(admin.TabularInline):
|
||||||
|
model = QuestionAnswer
|
||||||
|
|
||||||
|
class QuestionAnswerCategoryAdmin(admin.ModelAdmin):
|
||||||
|
inlines = (QuestionAnswerInline, )
|
||||||
|
|
||||||
|
|
||||||
|
admin.site.register(QuestionAnswerCategory, QuestionAnswerCategoryAdmin)
|
|
@ -0,0 +1,41 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import models, migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='QuestionAnswer',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||||
|
('ord', models.PositiveIntegerField(default=1)),
|
||||||
|
('title_es', models.CharField(max_length=256)),
|
||||||
|
('answer_es', models.TextField()),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
},
|
||||||
|
bases=(models.Model,),
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='QuestionAnswerCategory',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||||
|
('name_es', models.CharField(max_length=32)),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
},
|
||||||
|
bases=(models.Model,),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='questionanswer',
|
||||||
|
name='category',
|
||||||
|
field=models.ForeignKey(to='faq.QuestionAnswerCategory'),
|
||||||
|
preserve_default=True,
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,47 @@
|
||||||
|
# coding: utf-8
|
||||||
|
|
||||||
|
# django
|
||||||
|
from django.db import models
|
||||||
|
from django.utils.translation import get_language, ugettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
|
class QuestionAnswerCategory(models.Model):
|
||||||
|
name_es = models.CharField(max_length=32)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
ordering = ('name_es', )
|
||||||
|
verbose_name = _('Category')
|
||||||
|
verbose_name_plural = _('Categories')
|
||||||
|
|
||||||
|
def __unicode__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
return getattr(self, u'name_{}'.format(get_language()), u'')
|
||||||
|
|
||||||
|
|
||||||
|
class QuestionAnswer(models.Model):
|
||||||
|
category = models.ForeignKey(QuestionAnswerCategory,
|
||||||
|
related_name='questions')
|
||||||
|
ord = models.PositiveIntegerField(default=1)
|
||||||
|
|
||||||
|
# Spanish
|
||||||
|
title_es = models.CharField(max_length=256)
|
||||||
|
answer_es = models.TextField()
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
ordering = ('ord', )
|
||||||
|
verbose_name = _('Question')
|
||||||
|
verbose_name_plural = _('Questions')
|
||||||
|
|
||||||
|
def __unicode__(self):
|
||||||
|
return self.title
|
||||||
|
|
||||||
|
@property
|
||||||
|
def title(self):
|
||||||
|
return getattr(self, u'title_{}'.format(get_language()), u'')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def answer(self):
|
||||||
|
return getattr(self, u'answer_{}'.format(get_language()), u'')
|
|
@ -0,0 +1,3 @@
|
||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
# Create your tests here.
|
|
@ -0,0 +1,12 @@
|
||||||
|
# coding: utf-8
|
||||||
|
|
||||||
|
# django
|
||||||
|
from django.conf.urls import patterns, url
|
||||||
|
|
||||||
|
# app
|
||||||
|
from .views import FaqListView
|
||||||
|
|
||||||
|
urlpatterns = patterns(
|
||||||
|
'',
|
||||||
|
url(r'^$', FaqListView.as_view(), name='faq.list'),
|
||||||
|
)
|
|
@ -0,0 +1,26 @@
|
||||||
|
# coding: utf-8
|
||||||
|
|
||||||
|
# django
|
||||||
|
from django.views.generic import View
|
||||||
|
from django.template import RequestContext
|
||||||
|
from django.shortcuts import render_to_response
|
||||||
|
from django.db.models import Count
|
||||||
|
from django.contrib.auth import get_user_model
|
||||||
|
|
||||||
|
# shelfzilla.faq
|
||||||
|
from .models import QuestionAnswerCategory
|
||||||
|
|
||||||
|
|
||||||
|
class FaqListView(View):
|
||||||
|
template = 'faq/list.html'
|
||||||
|
|
||||||
|
def get(self, request):
|
||||||
|
data = {
|
||||||
|
'categories': QuestionAnswerCategory.objects.all(),
|
||||||
|
'navigation': {
|
||||||
|
'section': 'faqs',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx = RequestContext(request, data)
|
||||||
|
return render_to_response(self.template, context_instance=ctx)
|
|
@ -0,0 +1,16 @@
|
||||||
|
# coding: utf-8
|
||||||
|
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
from .models import Email
|
||||||
|
|
||||||
|
|
||||||
|
class RegistrationEmail(Email):
|
||||||
|
template = 'mailing/registration.html'
|
||||||
|
subject = _('Bienvenido a Shelfzilla')
|
||||||
|
|
||||||
|
# Context requires:
|
||||||
|
# - user: <User model>
|
||||||
|
|
||||||
|
def prepare(self):
|
||||||
|
self.recipients.append(self.context['user'].email)
|
|
@ -0,0 +1,53 @@
|
||||||
|
# coding: utf-8
|
||||||
|
|
||||||
|
from django.template import Context, Template
|
||||||
|
from django.template.loader import get_template
|
||||||
|
from django.utils.html import strip_tags
|
||||||
|
from django.core.mail import EmailMultiAlternatives
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
|
|
||||||
|
class Email(object):
|
||||||
|
template = ''
|
||||||
|
context = {}
|
||||||
|
|
||||||
|
subject = ''
|
||||||
|
from_email = None
|
||||||
|
recipients = []
|
||||||
|
text = ''
|
||||||
|
|
||||||
|
def __init__(self, context={}):
|
||||||
|
self.from_email = getattr(settings, 'FROM_EMAIL', 'root@localhost')
|
||||||
|
self.context = context
|
||||||
|
self.recipients = []
|
||||||
|
self.prepare()
|
||||||
|
|
||||||
|
def prepare(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def compile_template(self):
|
||||||
|
tmpl = get_template(self.template)
|
||||||
|
self.html = tmpl.render(Context(self.context))
|
||||||
|
self.text = strip_tags(self.html)
|
||||||
|
|
||||||
|
def send(self):
|
||||||
|
if self.template:
|
||||||
|
self.compile_template()
|
||||||
|
|
||||||
|
message = EmailMultiAlternatives(self.subject,
|
||||||
|
self.text,
|
||||||
|
self.from_email,
|
||||||
|
self.recipients)
|
||||||
|
|
||||||
|
if self.template:
|
||||||
|
message.attach_alternative(self.html, "text/html")
|
||||||
|
|
||||||
|
message.send()
|
||||||
|
|
||||||
|
|
||||||
|
# subject, from_email, to = 'hello', 'from@example.com', 'to@example.com'
|
||||||
|
# text_content = 'This is an important message.'
|
||||||
|
# html_content = '<p>This is an <strong>important</strong> message.</p>'
|
||||||
|
# msg = EmailMultiAlternatives(subject, text_content, from_email, [to])
|
||||||
|
# msg.attach_alternative(html_content, "text/html")
|
||||||
|
# msg.send()
|
|
@ -88,11 +88,13 @@ admin.site.register(Publisher, PublisherAdmin)
|
||||||
class SeriesSummaryInline(admin.TabularInline):
|
class SeriesSummaryInline(admin.TabularInline):
|
||||||
model = SeriesSummary
|
model = SeriesSummary
|
||||||
fields = ('summary', 'language', )
|
fields = ('summary', 'language', )
|
||||||
|
suit_classes = 'suit-tab suit-tab-summaries'
|
||||||
|
|
||||||
|
|
||||||
class SeriesPublisherInline(admin.TabularInline):
|
class SeriesPublisherInline(admin.TabularInline):
|
||||||
model = SeriesPublisher
|
model = SeriesPublisher
|
||||||
fields = ('publisher', 'status', 'actual_publisher')
|
fields = ('publisher', 'status', 'actual_publisher')
|
||||||
|
suit_classes = 'suit-tab suit-tab-publishers'
|
||||||
|
|
||||||
|
|
||||||
class SeriesAdmin(ImportExportModelAdmin, reversion.VersionAdmin):
|
class SeriesAdmin(ImportExportModelAdmin, reversion.VersionAdmin):
|
||||||
|
@ -107,7 +109,9 @@ class SeriesAdmin(ImportExportModelAdmin, reversion.VersionAdmin):
|
||||||
|
|
||||||
suit_form_tabs = (
|
suit_form_tabs = (
|
||||||
('general', _('General')),
|
('general', _('General')),
|
||||||
|
('publishers', _('Publishers')),
|
||||||
('volumes', _('Volumes')),
|
('volumes', _('Volumes')),
|
||||||
|
('summaries', _('Summary')),
|
||||||
('review', _('Review')),
|
('review', _('Review')),
|
||||||
('advanced', _('Advanced')),
|
('advanced', _('Advanced')),
|
||||||
)
|
)
|
||||||
|
@ -198,6 +202,7 @@ admin.site.register(Volume, VolumeAdmin)
|
||||||
|
|
||||||
class PersonAdmin(ImportExportModelAdmin, reversion.VersionAdmin):
|
class PersonAdmin(ImportExportModelAdmin, reversion.VersionAdmin):
|
||||||
resource_class = PersonResource
|
resource_class = PersonResource
|
||||||
|
search_fields = ('name', )
|
||||||
suit_form_tabs = (
|
suit_form_tabs = (
|
||||||
('general', _('General')),
|
('general', _('General')),
|
||||||
('review', _('Review')),
|
('review', _('Review')),
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
# coding: utf-8
|
||||||
|
|
||||||
|
# django
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
|
# third party
|
||||||
|
from easy_thumbnails.files import get_thumbnailer
|
||||||
|
from rest_framework import serializers
|
||||||
|
|
||||||
|
# own
|
||||||
|
from ..models import Volume, Series, Publisher, Person, Language
|
||||||
|
|
||||||
|
|
||||||
|
class LanguageSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = Language
|
||||||
|
fields = ('name', )
|
||||||
|
|
||||||
|
|
||||||
|
class PersonSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = Person
|
||||||
|
fields = ('name',)
|
||||||
|
|
||||||
|
|
||||||
|
class PublisherSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = Publisher
|
||||||
|
fields = ('id', 'name', 'url', )
|
||||||
|
|
||||||
|
|
||||||
|
class SeriesSerializer(serializers.ModelSerializer):
|
||||||
|
original_publisher = PublisherSerializer()
|
||||||
|
art = PersonSerializer(many=True)
|
||||||
|
story = PersonSerializer(many=True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = Series
|
||||||
|
fields = ('id', 'name', 'status', 'art', 'story', 'original_publisher')
|
||||||
|
|
||||||
|
|
||||||
|
class VolumeSerializer(serializers.ModelSerializer):
|
||||||
|
series = SeriesSerializer()
|
||||||
|
publisher = PublisherSerializer()
|
||||||
|
language = LanguageSerializer()
|
||||||
|
cover = serializers.SerializerMethodField('get_cover_thumbnail')
|
||||||
|
|
||||||
|
def get_cover_thumbnail(self, obj):
|
||||||
|
if obj.cover:
|
||||||
|
url = get_thumbnailer(obj.cover).get_thumbnail({
|
||||||
|
'size': (100, 100), 'crop': 'scale', 'autocrop': True,
|
||||||
|
}).url
|
||||||
|
return url
|
||||||
|
return None
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = Volume
|
||||||
|
fields = ('id', 'series', 'number', 'name', 'retail_price',
|
||||||
|
'release_date', 'publisher', 'cover', 'language')
|
|
@ -0,0 +1,13 @@
|
||||||
|
# coding: utf-8
|
||||||
|
|
||||||
|
# third
|
||||||
|
from rest_framework.routers import DefaultRouter
|
||||||
|
|
||||||
|
# own
|
||||||
|
from .views import VolumesViewSet
|
||||||
|
|
||||||
|
|
||||||
|
router = DefaultRouter(trailing_slash=False)
|
||||||
|
router.register(r'volumes', VolumesViewSet)
|
||||||
|
|
||||||
|
urlpatterns = router.urls
|
|
@ -0,0 +1,22 @@
|
||||||
|
# coding: utf-8
|
||||||
|
|
||||||
|
# third
|
||||||
|
from rest_framework import viewsets, filters
|
||||||
|
from rest_framework.permissions import IsAuthenticated
|
||||||
|
|
||||||
|
# own
|
||||||
|
from .serializers import VolumeSerializer
|
||||||
|
from ..models import Volume
|
||||||
|
|
||||||
|
|
||||||
|
class VolumesViewSet(viewsets.ReadOnlyModelViewSet):
|
||||||
|
"""
|
||||||
|
"""
|
||||||
|
# permission_classes = (IsAuthenticated,)
|
||||||
|
serializer_class = VolumeSerializer
|
||||||
|
queryset = Volume.objects.filter(hidden=False)
|
||||||
|
paginate_by = 20
|
||||||
|
|
||||||
|
filter_fields = ('series', )
|
||||||
|
filter_backends = (filters.SearchFilter,)
|
||||||
|
search_fields = ('name', 'number', 'series__name', )
|
|
@ -261,7 +261,7 @@ class UserHaveVolume(models.Model):
|
||||||
return self._timeline_message % {'volume': self.volume}
|
return self._timeline_message % {'volume': self.volume}
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return "{} {} {}".format(
|
return u"{} {} {}".format(
|
||||||
self.user.username,
|
self.user.username,
|
||||||
_('have'),
|
_('have'),
|
||||||
self.volume
|
self.volume
|
||||||
|
@ -289,7 +289,7 @@ class UserWishlistVolume(models.Model):
|
||||||
return self._timeline_message % {'volume': self.volume}
|
return self._timeline_message % {'volume': self.volume}
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return "{} {} {}".format(
|
return u"{} {} {}".format(
|
||||||
self.user.username,
|
self.user.username,
|
||||||
_('wants'),
|
_('wants'),
|
||||||
self.volume
|
self.volume
|
||||||
|
@ -317,7 +317,7 @@ class UserReadVolume(models.Model):
|
||||||
return self._timeline_message % {'volume': self.volume}
|
return self._timeline_message % {'volume': self.volume}
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return "{} {} {}".format(
|
return u"{} {} {}".format(
|
||||||
self.user.username,
|
self.user.username,
|
||||||
_('have read'),
|
_('have read'),
|
||||||
self.volume
|
self.volume
|
||||||
|
@ -386,8 +386,11 @@ def volume_check_filer(sender, instance, created, **kwargs):
|
||||||
|
|
||||||
|
|
||||||
def series_delete_folder(sender, instance, using, **kwargs):
|
def series_delete_folder(sender, instance, using, **kwargs):
|
||||||
|
try:
|
||||||
if instance.folder:
|
if instance.folder:
|
||||||
instance.folder.delete()
|
instance.folder.delete()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
def volume_delete_cover(sender, instance, **kwargs):
|
def volume_delete_cover(sender, instance, **kwargs):
|
||||||
|
|
Binary file not shown.
|
@ -8,9 +8,9 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2014-09-09 01:10+0200\n"
|
"POT-Creation-Date: 2015-01-26 14:45+0100\n"
|
||||||
"PO-Revision-Date: 2014-09-09 01:11+0200\n"
|
"PO-Revision-Date: 2015-01-26 14:45+0100\n"
|
||||||
"Last-Translator: Felipe Martin <fmartingr@me.com>\n"
|
"Last-Translator: <admin@admin.com>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
@ -19,18 +19,6 @@ msgstr ""
|
||||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
"X-Translated-Using: django-rosetta 0.7.4\n"
|
"X-Translated-Using: django-rosetta 0.7.4\n"
|
||||||
|
|
||||||
#: models.py:7
|
|
||||||
msgid "For review"
|
|
||||||
msgstr "Para revisión"
|
|
||||||
|
|
||||||
#: models.py:9
|
|
||||||
msgid "Review comment"
|
|
||||||
msgstr "Comentario de revisión"
|
|
||||||
|
|
||||||
#: models.py:11
|
|
||||||
msgid "Hidden"
|
|
||||||
msgstr "Oculto"
|
|
||||||
|
|
||||||
#: apps/_admin/views.py:44 apps/_admin/views.py:81
|
#: apps/_admin/views.py:44 apps/_admin/views.py:81
|
||||||
msgid "Volume series changed"
|
msgid "Volume series changed"
|
||||||
msgstr "Serie de los volúmenes cambiada"
|
msgstr "Serie de los volúmenes cambiada"
|
||||||
|
@ -43,6 +31,160 @@ msgstr "No se encontró la URL de la carátula para actualizar."
|
||||||
msgid "Volume not found."
|
msgid "Volume not found."
|
||||||
msgstr "Volumen no encontrado."
|
msgstr "Volumen no encontrado."
|
||||||
|
|
||||||
|
#: apps/account/admin.py:85
|
||||||
|
#, fuzzy
|
||||||
|
#| msgid "Person"
|
||||||
|
msgid "Personal info"
|
||||||
|
msgstr "Persona"
|
||||||
|
|
||||||
|
#: apps/account/admin.py:87
|
||||||
|
msgid "Permissions"
|
||||||
|
msgstr "Permisos"
|
||||||
|
|
||||||
|
#: apps/account/admin.py:88
|
||||||
|
msgid "Information"
|
||||||
|
msgstr "Información"
|
||||||
|
|
||||||
|
#: apps/account/forms.py:13 apps/account/models.py:40
|
||||||
|
msgid "Username"
|
||||||
|
msgstr "Usuario"
|
||||||
|
|
||||||
|
#: apps/account/forms.py:15 apps/account/forms.py:55
|
||||||
|
msgid "Password"
|
||||||
|
msgstr "Contraseña"
|
||||||
|
|
||||||
|
#: apps/account/forms.py:37
|
||||||
|
msgid "This account is disabled."
|
||||||
|
msgstr "Esta cuenta está desactivada."
|
||||||
|
|
||||||
|
#: apps/account/forms.py:41
|
||||||
|
msgid "User with those credentials was not found."
|
||||||
|
msgstr "No se ha encontrado un usuario con esos credenciales."
|
||||||
|
|
||||||
|
#: apps/account/forms.py:57
|
||||||
|
msgid "Repeat password"
|
||||||
|
msgstr "Repetir contraseña"
|
||||||
|
|
||||||
|
#: apps/account/forms.py:59
|
||||||
|
msgid "Invitation code"
|
||||||
|
msgstr "Código de invitacion"
|
||||||
|
|
||||||
|
#: apps/account/forms.py:75
|
||||||
|
msgid "Invitation code is not valid"
|
||||||
|
msgstr "El código de invitación no es válido"
|
||||||
|
|
||||||
|
#: apps/account/models.py:19
|
||||||
|
msgid "Male"
|
||||||
|
msgstr "Hombre"
|
||||||
|
|
||||||
|
#: apps/account/models.py:20
|
||||||
|
msgid "Female"
|
||||||
|
msgstr "Mujer"
|
||||||
|
|
||||||
|
#: apps/account/models.py:32
|
||||||
|
msgid "Email address"
|
||||||
|
msgstr "Correo electrónico"
|
||||||
|
|
||||||
|
#: apps/account/models.py:36
|
||||||
|
msgid "An user email that should be verified."
|
||||||
|
msgstr "Una dirección de correo electrónico que será verificada"
|
||||||
|
|
||||||
|
#: apps/account/models.py:48
|
||||||
|
msgid "First name"
|
||||||
|
msgstr "Nombre"
|
||||||
|
|
||||||
|
#: apps/account/models.py:53
|
||||||
|
msgid "Last name"
|
||||||
|
msgstr "Apellidos"
|
||||||
|
|
||||||
|
#: apps/account/models.py:58
|
||||||
|
msgid "Birthdate"
|
||||||
|
msgstr "Fecha de nacimiento"
|
||||||
|
|
||||||
|
#: apps/account/models.py:65
|
||||||
|
msgid "Gender"
|
||||||
|
msgstr "Sexo"
|
||||||
|
|
||||||
|
#: apps/account/models.py:73
|
||||||
|
msgid "Date joined"
|
||||||
|
msgstr "Fecha de registro"
|
||||||
|
|
||||||
|
#: apps/account/models.py:79
|
||||||
|
msgid "Active status"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: apps/account/models.py:81
|
||||||
|
msgid ""
|
||||||
|
"Designates whether this user should be treated as active. Unselect this "
|
||||||
|
"instead of deleting accounts."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: apps/account/models.py:86
|
||||||
|
msgid "Staff status"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: apps/account/models.py:88
|
||||||
|
msgid "Designates whether the user can log into this admin site."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: apps/account/models.py:103
|
||||||
|
msgid "User"
|
||||||
|
msgstr "Usuario"
|
||||||
|
|
||||||
|
#: apps/account/models.py:143 apps/manga/models.py:232
|
||||||
|
msgid "Code"
|
||||||
|
msgstr "Código"
|
||||||
|
|
||||||
|
#: apps/account/models.py:144
|
||||||
|
msgid "Number of uses"
|
||||||
|
msgstr "Número de usos"
|
||||||
|
|
||||||
|
#: apps/account/models.py:147
|
||||||
|
msgid "Expires"
|
||||||
|
msgstr "Expira"
|
||||||
|
|
||||||
|
#: apps/account/models.py:149
|
||||||
|
msgid "Active"
|
||||||
|
msgstr "Activo"
|
||||||
|
|
||||||
|
#: apps/account/models.py:152
|
||||||
|
msgid "Access code"
|
||||||
|
msgstr "Código de acceso"
|
||||||
|
|
||||||
|
#: apps/account/models.py:153
|
||||||
|
msgid "Access codes"
|
||||||
|
msgstr "Códigos de acceso"
|
||||||
|
|
||||||
|
#: apps/account/views.py:48
|
||||||
|
msgid "Logged in successfully."
|
||||||
|
msgstr "Has accedido correctamente."
|
||||||
|
|
||||||
|
#: apps/account/views.py:67
|
||||||
|
msgid "Logged out successfully"
|
||||||
|
msgstr "Sesión finalizada."
|
||||||
|
|
||||||
|
#: apps/account/views.py:134
|
||||||
|
msgid "Password changed."
|
||||||
|
msgstr "Contraseña cambiada."
|
||||||
|
|
||||||
|
#: apps/account/views.py:165
|
||||||
|
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
|
||||||
|
msgid "General"
|
||||||
|
msgstr "General"
|
||||||
|
|
||||||
|
#: apps/blog/admin.py:25
|
||||||
|
msgid "Content"
|
||||||
|
msgstr "Contenido"
|
||||||
|
|
||||||
|
#: apps/blog/templatetags/datetime.py:17
|
||||||
|
msgid "%B %e, %Y"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: apps/config/models.py:13 apps/config/models.py:16 apps/config/models.py:17
|
#: apps/config/models.py:13 apps/config/models.py:16 apps/config/models.py:17
|
||||||
msgid "Site Configuration"
|
msgid "Site Configuration"
|
||||||
msgstr "Configuración del sitio"
|
msgstr "Configuración del sitio"
|
||||||
|
@ -51,6 +193,10 @@ msgstr "Configuración del sitio"
|
||||||
msgid "Social Configuration"
|
msgid "Social Configuration"
|
||||||
msgstr "Configuración social"
|
msgstr "Configuración social"
|
||||||
|
|
||||||
|
#: apps/mailing/emails.py:10
|
||||||
|
msgid "Bienvenido a Shelfzilla"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: apps/manga/admin.py:44
|
#: apps/manga/admin.py:44
|
||||||
msgid "Items marked for review"
|
msgid "Items marked for review"
|
||||||
msgstr "Marcar items para revisión"
|
msgstr "Marcar items para revisión"
|
||||||
|
@ -59,11 +205,6 @@ msgstr "Marcar items para revisión"
|
||||||
msgid "Items unmarked for review"
|
msgid "Items unmarked for review"
|
||||||
msgstr "Desmarcar items para revisión"
|
msgstr "Desmarcar items para revisión"
|
||||||
|
|
||||||
#: 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
|
|
||||||
msgid "General"
|
|
||||||
msgstr "General"
|
|
||||||
|
|
||||||
#: apps/manga/admin.py:62 apps/manga/admin.py:111 apps/manga/admin.py:156
|
#: 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:203 apps/manga/admin.py:255
|
||||||
msgid "Review"
|
msgid "Review"
|
||||||
|
@ -75,7 +216,7 @@ msgid "Advanced"
|
||||||
msgstr "Avanzado"
|
msgstr "Avanzado"
|
||||||
|
|
||||||
#: apps/manga/admin.py:83 apps/manga/models.py:134 apps/manga/models.py:135
|
#: apps/manga/admin.py:83 apps/manga/models.py:134 apps/manga/models.py:135
|
||||||
#: themes/bootflat/templates/_layout.html:40
|
#: themes/bootflat/templates/_layout.html:39
|
||||||
#: themes/bootflat/templates/homepage/home.html:72
|
#: themes/bootflat/templates/homepage/home.html:72
|
||||||
#: themes/bootflat/templates/manga/publishers/detail.html:19
|
#: themes/bootflat/templates/manga/publishers/detail.html:19
|
||||||
#: themes/bootflat/templates/manga/series/list.html:4
|
#: themes/bootflat/templates/manga/series/list.html:4
|
||||||
|
@ -120,7 +261,7 @@ msgstr "URL"
|
||||||
msgid "Publisher"
|
msgid "Publisher"
|
||||||
msgstr "Editorial"
|
msgstr "Editorial"
|
||||||
|
|
||||||
#: apps/manga/models.py:54 themes/bootflat/templates/_layout.html:43
|
#: apps/manga/models.py:54 themes/bootflat/templates/_layout.html:42
|
||||||
#: themes/bootflat/templates/manga/publishers/list.html:4
|
#: themes/bootflat/templates/manga/publishers/list.html:4
|
||||||
#: themes/bootflat/templates/manga/series/detail.html:55
|
#: themes/bootflat/templates/manga/series/detail.html:55
|
||||||
msgid "Publishers"
|
msgid "Publishers"
|
||||||
|
@ -206,10 +347,6 @@ msgstr "Persona"
|
||||||
msgid "Persons"
|
msgid "Persons"
|
||||||
msgstr "Personas"
|
msgstr "Personas"
|
||||||
|
|
||||||
#: apps/manga/models.py:232
|
|
||||||
msgid "Code"
|
|
||||||
msgstr "Código"
|
|
||||||
|
|
||||||
#: apps/manga/models.py:239
|
#: apps/manga/models.py:239
|
||||||
#: themes/bootflat/templates/manga/series/detail.html:106
|
#: themes/bootflat/templates/manga/series/detail.html:106
|
||||||
msgid "Language"
|
msgid "Language"
|
||||||
|
@ -219,7 +356,7 @@ msgstr "Idioma"
|
||||||
msgid "Languages"
|
msgid "Languages"
|
||||||
msgstr "Idiomas"
|
msgstr "Idiomas"
|
||||||
|
|
||||||
#: apps/manga/models.py:250 apps/manga/models.py:273 apps/manga/models.py:296
|
#: apps/manga/models.py:250 apps/manga/models.py:278 apps/manga/models.py:306
|
||||||
msgid "Date"
|
msgid "Date"
|
||||||
msgstr "Fecha"
|
msgstr "Fecha"
|
||||||
|
|
||||||
|
@ -228,32 +365,32 @@ msgstr "Fecha"
|
||||||
msgid "%(volume)s added to collection"
|
msgid "%(volume)s added to collection"
|
||||||
msgstr "%(volume)s añadido a la colección"
|
msgstr "%(volume)s añadido a la colección"
|
||||||
|
|
||||||
#: apps/manga/models.py:261
|
#: apps/manga/models.py:266
|
||||||
msgid "have"
|
msgid "have"
|
||||||
msgstr "tiene"
|
msgstr "tiene"
|
||||||
|
|
||||||
#: apps/manga/models.py:275
|
#: apps/manga/models.py:280
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "%(volume)s wishlisted"
|
msgid "%(volume)s wishlisted"
|
||||||
msgstr "%(volume)s añadido a deseados"
|
msgstr "%(volume)s añadido a deseados"
|
||||||
|
|
||||||
#: apps/manga/models.py:284
|
#: apps/manga/models.py:294
|
||||||
msgid "wants"
|
msgid "wants"
|
||||||
msgstr "quiere"
|
msgstr "quiere"
|
||||||
|
|
||||||
#: apps/manga/models.py:298
|
#: apps/manga/models.py:308
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "%(volume)s marked as read"
|
msgid "%(volume)s marked as read"
|
||||||
msgstr "%(volume)s marcado como leído"
|
msgstr "%(volume)s marcado como leído"
|
||||||
|
|
||||||
#: apps/manga/models.py:307
|
#: apps/manga/models.py:322
|
||||||
msgid "have read"
|
msgid "have read"
|
||||||
msgstr "ha leído"
|
msgstr "ha leído"
|
||||||
|
|
||||||
#: apps/manga/views/search.py:11 apps/manga/views/search.py:13
|
#: apps/manga/views/search.py:11 apps/manga/views/search.py:13
|
||||||
#: themes/bootflat/templates/_layout.html:80
|
|
||||||
#: themes/bootflat/templates/_admin/volumes/includes/cover.html:6
|
#: themes/bootflat/templates/_admin/volumes/includes/cover.html:6
|
||||||
#: themes/bootflat/templates/_admin/volumes/includes/cover.html:15
|
#: themes/bootflat/templates/_admin/volumes/includes/cover.html:15
|
||||||
|
#: themes/bootflat/templates/_layout.html:83
|
||||||
msgid "Search"
|
msgid "Search"
|
||||||
msgstr "Buscar"
|
msgstr "Buscar"
|
||||||
|
|
||||||
|
@ -285,31 +422,19 @@ msgstr "{} marcado como no leído"
|
||||||
msgid "{} marked as read!"
|
msgid "{} marked as read!"
|
||||||
msgstr "¡{} marcado como leído!"
|
msgstr "¡{} marcado como leído!"
|
||||||
|
|
||||||
#: apps/users/forms.py:7
|
#: models.py:7
|
||||||
msgid "Username"
|
msgid "For review"
|
||||||
msgstr "Usuario"
|
msgstr "Para revisión"
|
||||||
|
|
||||||
#: apps/users/forms.py:9
|
#: models.py:9
|
||||||
msgid "Password"
|
msgid "Review comment"
|
||||||
msgstr "Contraseña"
|
msgstr "Comentario de revisión"
|
||||||
|
|
||||||
#: apps/users/forms.py:31
|
#: models.py:11
|
||||||
msgid "This account is disabled."
|
msgid "Hidden"
|
||||||
msgstr "Esta cuenta está desactivada."
|
msgstr "Oculto"
|
||||||
|
|
||||||
#: apps/users/forms.py:35
|
#: settings/base.py:131
|
||||||
msgid "User with those credentials was not found."
|
|
||||||
msgstr "No se ha encontrado un usuario con esos credenciales."
|
|
||||||
|
|
||||||
#: apps/users/views.py:44
|
|
||||||
msgid "Logged in successfully."
|
|
||||||
msgstr "Has accedido correctamente."
|
|
||||||
|
|
||||||
#: apps/users/views.py:63
|
|
||||||
msgid "Logged out successfully"
|
|
||||||
msgstr "Sesión finalizada."
|
|
||||||
|
|
||||||
#: settings/base.py:128
|
|
||||||
msgid "Spanish"
|
msgid "Spanish"
|
||||||
msgstr "Español"
|
msgstr "Español"
|
||||||
|
|
||||||
|
@ -329,25 +454,6 @@ msgstr ""
|
||||||
"Hubo un error interno del servidor. Puede ser temporal, pero si el problema "
|
"Hubo un error interno del servidor. Puede ser temporal, pero si el problema "
|
||||||
"persiste, contacta con nosotros."
|
"persiste, contacta con nosotros."
|
||||||
|
|
||||||
#: themes/bootflat/templates/_layout.html:27
|
|
||||||
msgid "Toggle navigation"
|
|
||||||
msgstr "Mostrar/Ocultar navegación"
|
|
||||||
|
|
||||||
#: themes/bootflat/templates/_layout.html:49
|
|
||||||
#: themes/bootflat/templates/_layout.html:57
|
|
||||||
#: themes/bootflat/templates/users/profile-pjax.html:4
|
|
||||||
#: themes/bootflat/templates/users/profile.html:4
|
|
||||||
msgid "Profile"
|
|
||||||
msgstr "Perfil"
|
|
||||||
|
|
||||||
#: themes/bootflat/templates/_layout.html:62
|
|
||||||
msgid "Logout"
|
|
||||||
msgstr "Cerrar sesión"
|
|
||||||
|
|
||||||
#: themes/bootflat/templates/_layout.html:69
|
|
||||||
msgid "Log in"
|
|
||||||
msgstr "Entrar"
|
|
||||||
|
|
||||||
#: themes/bootflat/templates/_admin/manga/series/includes/volumes.html:13
|
#: themes/bootflat/templates/_admin/manga/series/includes/volumes.html:13
|
||||||
msgid "Edit"
|
msgid "Edit"
|
||||||
msgstr "Editar"
|
msgstr "Editar"
|
||||||
|
@ -361,6 +467,7 @@ msgid "Change to: "
|
||||||
msgstr "Cambiar a:"
|
msgstr "Cambiar a:"
|
||||||
|
|
||||||
#: themes/bootflat/templates/_admin/volumes/change_series.html:28
|
#: themes/bootflat/templates/_admin/volumes/change_series.html:28
|
||||||
|
#: themes/bootflat/templates/account/main.html:61
|
||||||
msgid "Change"
|
msgid "Change"
|
||||||
msgstr "Cambiar"
|
msgstr "Cambiar"
|
||||||
|
|
||||||
|
@ -372,6 +479,41 @@ msgstr "Carátula actual:"
|
||||||
msgid "Update with this"
|
msgid "Update with this"
|
||||||
msgstr "Actualizar con esta"
|
msgstr "Actualizar con esta"
|
||||||
|
|
||||||
|
#: themes/bootflat/templates/_layout.html:27
|
||||||
|
msgid "Toggle navigation"
|
||||||
|
msgstr "Mostrar/Ocultar navegación"
|
||||||
|
|
||||||
|
#: themes/bootflat/templates/_layout.html:47
|
||||||
|
#: themes/bootflat/templates/_layout.html:55
|
||||||
|
#: 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
|
||||||
|
msgid "Logout"
|
||||||
|
msgstr "Cerrar sesión"
|
||||||
|
|
||||||
|
#: themes/bootflat/templates/_layout.html:67
|
||||||
|
#: themes/bootflat/templates/account/register.html:15
|
||||||
|
#: themes/bootflat/templates/account/register.html:46
|
||||||
|
msgid "Register"
|
||||||
|
msgstr "Registrarse"
|
||||||
|
|
||||||
|
#: themes/bootflat/templates/_layout.html:72
|
||||||
|
msgid "Log in"
|
||||||
|
msgstr "Entrar"
|
||||||
|
|
||||||
|
#: themes/bootflat/templates/account/_layout.html:4
|
||||||
|
msgid "Account"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: themes/bootflat/templates/account/main.html:31
|
||||||
|
#, fuzzy
|
||||||
|
#| msgid "Change to: "
|
||||||
|
msgid "Change password"
|
||||||
|
msgstr "Cambiar a:"
|
||||||
|
|
||||||
#: themes/bootflat/templates/homepage/home.html:10
|
#: themes/bootflat/templates/homepage/home.html:10
|
||||||
msgid "Upcoming volumes"
|
msgid "Upcoming volumes"
|
||||||
msgstr "Futuros lanzamientos"
|
msgstr "Futuros lanzamientos"
|
||||||
|
@ -397,6 +539,16 @@ msgstr "Estadísticas"
|
||||||
msgid "Users"
|
msgid "Users"
|
||||||
msgstr "Usuarios"
|
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
|
||||||
|
msgid "Edit in admin"
|
||||||
|
msgstr "Editar en el admin"
|
||||||
|
|
||||||
|
#: themes/bootflat/templates/manga/publishers/detail.html:26
|
||||||
|
msgid "Homepage"
|
||||||
|
msgstr "Página principal"
|
||||||
|
|
||||||
#: themes/bootflat/templates/manga/search.html:8
|
#: themes/bootflat/templates/manga/search.html:8
|
||||||
msgid "Looking for..."
|
msgid "Looking for..."
|
||||||
msgstr "Buscando..."
|
msgstr "Buscando..."
|
||||||
|
@ -407,16 +559,6 @@ msgstr "Buscando..."
|
||||||
msgid "No results"
|
msgid "No results"
|
||||||
msgstr "Sin resultados"
|
msgstr "Sin resultados"
|
||||||
|
|
||||||
#: themes/bootflat/templates/manga/publishers/detail.html:10
|
|
||||||
#: themes/bootflat/templates/manga/series/detail.html:10
|
|
||||||
#: themes/bootflat/templates/manga/series/includes/volume.html:47
|
|
||||||
msgid "Edit in admin"
|
|
||||||
msgstr "Editar en el admin"
|
|
||||||
|
|
||||||
#: themes/bootflat/templates/manga/publishers/detail.html:26
|
|
||||||
msgid "Homepage"
|
|
||||||
msgstr "Página principal"
|
|
||||||
|
|
||||||
#: themes/bootflat/templates/manga/series/detail.html:26
|
#: themes/bootflat/templates/manga/series/detail.html:26
|
||||||
msgid "Art"
|
msgid "Art"
|
||||||
msgstr "Arte"
|
msgstr "Arte"
|
||||||
|
@ -443,20 +585,20 @@ msgstr "Todos"
|
||||||
msgid "Filter"
|
msgid "Filter"
|
||||||
msgstr "Filtrar"
|
msgstr "Filtrar"
|
||||||
|
|
||||||
#: themes/bootflat/templates/manga/series/list.html:17
|
#: themes/bootflat/templates/manga/series/includes/volume.html:44
|
||||||
msgid "other"
|
|
||||||
msgstr "otros"
|
|
||||||
|
|
||||||
#: themes/bootflat/templates/manga/series/includes/volume.html:39
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "%(pages)s pages"
|
msgid "%(pages)s pages"
|
||||||
msgstr "%(pages)s páginas"
|
msgstr "%(pages)s páginas"
|
||||||
|
|
||||||
#: themes/bootflat/templates/users/login.html:24
|
#: themes/bootflat/templates/manga/series/list.html:17
|
||||||
|
msgid "other"
|
||||||
|
msgstr "otros"
|
||||||
|
|
||||||
|
#: themes/bootflat/templates/users/login.html:27
|
||||||
msgid "Access the site"
|
msgid "Access the site"
|
||||||
msgstr "Accede al sitio"
|
msgstr "Accede al sitio"
|
||||||
|
|
||||||
#: themes/bootflat/templates/users/login.html:41
|
#: themes/bootflat/templates/users/login.html:45
|
||||||
msgid "Login"
|
msgid "Login"
|
||||||
msgstr "Entrar"
|
msgstr "Entrar"
|
||||||
|
|
||||||
|
@ -469,10 +611,6 @@ msgstr "Lista de deseados"
|
||||||
msgid "Edit my profile"
|
msgid "Edit my profile"
|
||||||
msgstr "Editar mi perfil"
|
msgstr "Editar mi perfil"
|
||||||
|
|
||||||
#: themes/bootflat/templates/users/profile.html:50
|
|
||||||
msgid "My preferences"
|
|
||||||
msgstr "Mis preferencias"
|
|
||||||
|
|
||||||
#: themes/bootflat/templates/users/profile/achievements.html:4
|
#: themes/bootflat/templates/users/profile/achievements.html:4
|
||||||
msgid "Achievements"
|
msgid "Achievements"
|
||||||
msgstr "Logros"
|
msgstr "Logros"
|
||||||
|
@ -494,6 +632,9 @@ msgstr "Volúmenes"
|
||||||
msgid "Volumes wishlisted"
|
msgid "Volumes wishlisted"
|
||||||
msgstr "Deseados"
|
msgstr "Deseados"
|
||||||
|
|
||||||
|
#~ msgid "My preferences"
|
||||||
|
#~ msgstr "Mis preferencias"
|
||||||
|
|
||||||
#~ msgid "Requires review"
|
#~ msgid "Requires review"
|
||||||
#~ msgstr "Requiere revisión"
|
#~ msgstr "Requiere revisión"
|
||||||
|
|
||||||
|
|
|
@ -65,10 +65,18 @@ INSTALLED_APPS = (
|
||||||
'shelfzilla.apps._admin',
|
'shelfzilla.apps._admin',
|
||||||
'shelfzilla.apps.config',
|
'shelfzilla.apps.config',
|
||||||
'shelfzilla.apps.homepage',
|
'shelfzilla.apps.homepage',
|
||||||
'shelfzilla.apps.landing',
|
# 'shelfzilla.apps.landing',
|
||||||
|
'shelfzilla.apps.mailing',
|
||||||
'shelfzilla.apps.manga',
|
'shelfzilla.apps.manga',
|
||||||
'shelfzilla.apps.blog',
|
'shelfzilla.apps.blog',
|
||||||
|
'shelfzilla.apps.faq',
|
||||||
'shelfzilla.apps.pjax',
|
'shelfzilla.apps.pjax',
|
||||||
|
|
||||||
|
# API
|
||||||
|
'corsheaders',
|
||||||
|
'rest_framework',
|
||||||
|
'rest_framework.authtoken',
|
||||||
|
'djoser',
|
||||||
)
|
)
|
||||||
|
|
||||||
TEMPLATE_CONTEXT_PROCESSORS = (
|
TEMPLATE_CONTEXT_PROCESSORS = (
|
||||||
|
@ -93,6 +101,7 @@ TEMPLATE_CONTEXT_PROCESSORS = (
|
||||||
MIDDLEWARE_CLASSES = (
|
MIDDLEWARE_CLASSES = (
|
||||||
'reversion.middleware.RevisionMiddleware',
|
'reversion.middleware.RevisionMiddleware',
|
||||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||||
|
'corsheaders.middleware.CorsMiddleware',
|
||||||
'django.middleware.common.CommonMiddleware',
|
'django.middleware.common.CommonMiddleware',
|
||||||
'django.middleware.locale.LocaleMiddleware',
|
'django.middleware.locale.LocaleMiddleware',
|
||||||
'django.middleware.csrf.CsrfViewMiddleware',
|
'django.middleware.csrf.CsrfViewMiddleware',
|
||||||
|
@ -255,7 +264,7 @@ SUIT_CONFIG = {
|
||||||
{
|
{
|
||||||
'label': 'Authorization',
|
'label': 'Authorization',
|
||||||
'icon': 'icon-lock',
|
'icon': 'icon-lock',
|
||||||
'models': ('account.user', 'auth.group')
|
'models': ('account.user', 'auth.group', 'account.accesscode', )
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'app': 'config',
|
'app': 'config',
|
||||||
|
@ -272,6 +281,11 @@ SUIT_CONFIG = {
|
||||||
'label': 'Manga',
|
'label': 'Manga',
|
||||||
'icon': 'icon-book',
|
'icon': 'icon-book',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
'app': 'faq',
|
||||||
|
'label': 'FAQs',
|
||||||
|
'icon': 'icon-book',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
'label': 'Files',
|
'label': 'Files',
|
||||||
'icon': 'icon-file',
|
'icon': 'icon-file',
|
||||||
|
@ -296,3 +310,24 @@ CKEDITOR_CONFIGS = {
|
||||||
# AUTH
|
# AUTH
|
||||||
#
|
#
|
||||||
AUTH_USER_MODEL = 'account.User'
|
AUTH_USER_MODEL = 'account.User'
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# API
|
||||||
|
#
|
||||||
|
CORS_ORIGIN_ALLOW_ALL = True
|
||||||
|
|
||||||
|
REST_FRAMEWORK = {
|
||||||
|
'DEFAULT_AUTHENTICATION_CLASSES': (
|
||||||
|
'rest_framework.authentication.TokenAuthentication',
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
DJOSER = {
|
||||||
|
'DOMAIN': 'shelfzilla.com',
|
||||||
|
'SITE_NAME': 'Shelfzilla',
|
||||||
|
'PASSWORD_RESET_CONFIRM_URL': '#/password/reset/confirm/{uid}/{token}',
|
||||||
|
'ACTIVATION_URL': '#/activate/{uid}/{token}',
|
||||||
|
'LOGIN_AFTER_ACTIVATION': True,
|
||||||
|
'SEND_ACTIVATION_EMAIL': False,
|
||||||
|
}
|
||||||
|
|
|
@ -14,6 +14,17 @@ with open(os.environ['APP_CONFIGFILE']) as conffile:
|
||||||
# Installed Apps
|
# Installed Apps
|
||||||
INSTALLED_APPS += tuple(config['global']['installed_apps'])
|
INSTALLED_APPS += tuple(config['global']['installed_apps'])
|
||||||
|
|
||||||
|
# Middleware classes
|
||||||
|
if 'middleware_classes' in config['global']:
|
||||||
|
if 'prepend' in config['global']['middleware_classes']:
|
||||||
|
MIDDLEWARE_CLASSES = MIDDLEWARE_CLASSES + tuple(
|
||||||
|
config['global']['middleware_classes']['prepend']
|
||||||
|
)
|
||||||
|
if 'append' in config['global']['middleware_classes']:
|
||||||
|
MIDDLEWARE_CLASSES += tuple(
|
||||||
|
config['global']['middleware_classes']['append']
|
||||||
|
)
|
||||||
|
|
||||||
# Database
|
# Database
|
||||||
DATABASES = {
|
DATABASES = {
|
||||||
'default': dj_database_url.parse(config['global']['database_url'])
|
'default': dj_database_url.parse(config['global']['database_url'])
|
||||||
|
@ -75,13 +86,27 @@ FILER_STORAGES = {
|
||||||
# Logging
|
# Logging
|
||||||
LOGGING = {
|
LOGGING = {
|
||||||
'version': 1,
|
'version': 1,
|
||||||
'disable_existing_loggers': False,
|
'disable_existing_loggers': True,
|
||||||
|
'formatters': {
|
||||||
|
'verbose': {
|
||||||
|
'format': '%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s'
|
||||||
|
},
|
||||||
|
},
|
||||||
'handlers': {
|
'handlers': {
|
||||||
'file': {
|
'file': {
|
||||||
'level': 'DEBUG',
|
'level': 'DEBUG',
|
||||||
'class': 'logging.FileHandler',
|
'class': 'logging.FileHandler',
|
||||||
'filename': config['log']['logfile'],
|
'filename': config['log']['logfile'],
|
||||||
},
|
},
|
||||||
|
'opbeat': {
|
||||||
|
'level': 'WARNING',
|
||||||
|
'class': 'opbeat.contrib.django.handlers.OpbeatHandler',
|
||||||
|
},
|
||||||
|
'console': {
|
||||||
|
'level': 'DEBUG',
|
||||||
|
'class': 'logging.StreamHandler',
|
||||||
|
'formatter': 'verbose'
|
||||||
|
}
|
||||||
},
|
},
|
||||||
'loggers': {
|
'loggers': {
|
||||||
'django.request': {
|
'django.request': {
|
||||||
|
@ -89,5 +114,21 @@ LOGGING = {
|
||||||
'level': 'DEBUG',
|
'level': 'DEBUG',
|
||||||
'propagate': True,
|
'propagate': True,
|
||||||
},
|
},
|
||||||
|
'django.db.backends': {
|
||||||
|
'level': 'ERROR',
|
||||||
|
'handlers': ['console'],
|
||||||
|
'propagate': False,
|
||||||
|
},
|
||||||
|
'shelfzilla': {
|
||||||
|
'level': 'WARNING',
|
||||||
|
'handlers': ['opbeat'],
|
||||||
|
'propagate': False,
|
||||||
|
},
|
||||||
|
# Log errors from the Opbeat module to the console (recommended)
|
||||||
|
'opbeat.errors': {
|
||||||
|
'level': 'ERROR',
|
||||||
|
'handlers': ['console'],
|
||||||
|
'propagate': False,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,3 +30,8 @@ FILER_DUMP_PAYLOAD = True
|
||||||
|
|
||||||
MEDIA_URL = '/media/'
|
MEDIA_URL = '/media/'
|
||||||
STATIC_URL = '/static/'
|
STATIC_URL = '/static/'
|
||||||
|
|
||||||
|
EMAIL_BACKEND = 'django_mailgun.MailgunBackend'
|
||||||
|
MAILGUN_ACCESS_KEY = 'key-fdfc57f2bfb35a4ba5f9c1e3c30af373'
|
||||||
|
MAILGUN_SERVER_NAME = 'sandbox2dd21e486d144dc59742738b15e494ee.mailgun.org'
|
||||||
|
FROM_EMAIL = 'info@shelfzilla.com'
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 260 B |
Binary file not shown.
After Width: | Height: | Size: 367 B |
Binary file not shown.
After Width: | Height: | Size: 366 B |
Binary file not shown.
After Width: | Height: | Size: 366 B |
Binary file not shown.
After Width: | Height: | Size: 369 B |
|
@ -1,4 +1,9 @@
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% if original %}
|
||||||
|
<a class="btn btn-info pull-right" href="{% url "admin:manga_volume_add" %}?series={{ original.pk }}">{% trans "Add" %} {% trans "Volume" %}</a>
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
<table class="table table-striped table-bordered table-hover table-condensed">
|
<table class="table table-striped table-bordered table-hover table-condensed">
|
||||||
<thead>
|
<thead>
|
||||||
<th> </th>
|
<th> </th>
|
||||||
|
@ -15,4 +20,4 @@
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
{% endif %}
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
<script>
|
<script type="text/javascript">
|
||||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
var _gaq = _gaq || [];
|
||||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
_gaq.push(['_setAccount', '{{ social_config.google_analytics }}']);
|
||||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
_gaq.push(['_trackPageview']);
|
||||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
|
||||||
|
|
||||||
ga('create', '{{ social_config.google_analytics }}', '{{ request.get_host }}');
|
(function() {
|
||||||
ga('send', 'pageview');
|
var ga = document.createElement('script');
|
||||||
|
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
||||||
|
ga.setAttribute('async', 'true');
|
||||||
|
document.documentElement.firstChild.appendChild(ga);
|
||||||
|
})();
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -15,6 +15,9 @@
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% endcompress %}
|
{% endcompress %}
|
||||||
<title>{% block page_title %}ShelfZilla{% endblock %}</title>
|
<title>{% block page_title %}ShelfZilla{% endblock %}</title>
|
||||||
|
{% if social_config.google_analytics %}
|
||||||
|
{% include "_includes/google_analytics.html" %}
|
||||||
|
{% endif %}
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
{% block navigation_bar %}
|
{% block navigation_bar %}
|
||||||
|
@ -34,7 +37,6 @@
|
||||||
|
|
||||||
<!-- Collect the nav links, forms, and other content for toggling -->
|
<!-- Collect the nav links, forms, and other content for toggling -->
|
||||||
<div class="collapse navbar-collapse" id="navbar-collapse">
|
<div class="collapse navbar-collapse" id="navbar-collapse">
|
||||||
{% if user.is_authenticated %}
|
|
||||||
<ul class="nav navbar-nav">
|
<ul class="nav navbar-nav">
|
||||||
<li data-pjax-nav {% if navigation.section == "series" %}class="active"{% endif %}>
|
<li data-pjax-nav {% if navigation.section == "series" %}class="active"{% endif %}>
|
||||||
<a data-pjax href="{% url "series.list" %}">{% trans "Series" %}</a>
|
<a data-pjax href="{% url "series.list" %}">{% trans "Series" %}</a>
|
||||||
|
@ -42,8 +44,12 @@
|
||||||
<li data-pjax-nav {% if navigation.section == "publishers" %}class="active"{% endif %}>
|
<li data-pjax-nav {% if navigation.section == "publishers" %}class="active"{% endif %}>
|
||||||
<a data-pjax href="{% url 'publishers.list' %}">{% trans "Publishers" %}</a>
|
<a data-pjax href="{% url 'publishers.list' %}">{% trans "Publishers" %}</a>
|
||||||
</li>
|
</li>
|
||||||
|
<!--
|
||||||
|
<li data-pjax-nav {% if navigation.section == "faqs" %}class="active"{% endif %}>
|
||||||
|
<a data-pjax href="{% url 'faq.list' %}">{% trans "Faq" %}</a>
|
||||||
|
</li>
|
||||||
|
-->
|
||||||
</ul>
|
</ul>
|
||||||
{% endif %}
|
|
||||||
<ul class="nav navbar-nav navbar-right">
|
<ul class="nav navbar-nav navbar-right">
|
||||||
{% if user.is_authenticated %}
|
{% if user.is_authenticated %}
|
||||||
<li><a href="{% url 'profile' user.username %}" title="{% trans "Profile" %}" data-toggle="tooltip" data-placement="bottom">
|
<li><a href="{% url 'profile' user.username %}" title="{% trans "Profile" %}" data-toggle="tooltip" data-placement="bottom">
|
||||||
|
@ -64,6 +70,11 @@
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
{% else %}
|
{% else %}
|
||||||
|
<li>
|
||||||
|
<a href="{% url "register" %}">
|
||||||
|
<i class="glyphicon glyphicon-pencil"></i> {% trans "Register" %}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="{% url "login" %}">
|
<a href="{% url "login" %}">
|
||||||
<i class="glyphicon glyphicon-log-in"></i> {% trans "Log in" %}
|
<i class="glyphicon glyphicon-log-in"></i> {% trans "Log in" %}
|
||||||
|
@ -100,7 +111,7 @@
|
||||||
var USE_PJAX = {{ site_config.use_pjax|lower }};
|
var USE_PJAX = {{ site_config.use_pjax|lower }};
|
||||||
</script>
|
</script>
|
||||||
<script type="text/javascript" src="{% static "bower/jquery/dist/jquery.js" %}"></script>
|
<script type="text/javascript" src="{% static "bower/jquery/dist/jquery.js" %}"></script>
|
||||||
<script type="text/javascript" src="{% static "bower/Bootflat/js/bootstrap.min.js" %}"></script>
|
<script type="text/javascript" src="{% static "bower/bootflatv2/js/bootstrap.min.js" %}"></script>
|
||||||
<script type="text/javascript" src="{% static "bower/jquery-pjax/jquery.pjax.js" %}"></script>
|
<script type="text/javascript" src="{% static "bower/jquery-pjax/jquery.pjax.js" %}"></script>
|
||||||
<script type="text/javascript" src="{% static "bower/nprogress/nprogress.js" %}"></script>
|
<script type="text/javascript" src="{% static "bower/nprogress/nprogress.js" %}"></script>
|
||||||
<script type="text/javascript" src="{% static "bower/toastr/toastr.js" %}"></script>
|
<script type="text/javascript" src="{% static "bower/toastr/toastr.js" %}"></script>
|
||||||
|
@ -113,9 +124,5 @@
|
||||||
{% if not USER_CONFIG.use_pjax %}
|
{% if not USER_CONFIG.use_pjax %}
|
||||||
<script type="text/javascript">$(function() { window.updateMessages(); });</script>
|
<script type="text/javascript">$(function() { window.updateMessages(); });</script>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if social_config.google_analytics %}
|
|
||||||
{% include "_includes/google_analytics.html" %}
|
|
||||||
{% endif %}
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
{% extends "_layout.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block main_content %}
|
||||||
|
<div class="container">
|
||||||
|
<div class="alert alert-info text-center">
|
||||||
|
Para registrarte en Shelfzilla necesitarás un <strong>código de invitación</strong>. Los registros abiertos no están disponibles por el momento.<br />
|
||||||
|
Permanece atento a nuestras redes sociales, ¡pronto empezaremos a repatir!
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-3"></div>
|
||||||
|
<div class="col-sm-6" >
|
||||||
|
<div class="panel panel-primary">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<h1 class="panel-title">{% trans "Register" %}</h1>
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<form class="form-horizontal" role="form" method="post" action=".">
|
||||||
|
{% csrf_token %}
|
||||||
|
{% for field in form %}
|
||||||
|
<div class="has-error text-right">
|
||||||
|
{% for error in field.errors %}
|
||||||
|
<span class="badge badge-danger">{{ error }}</span>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
<div class="form-group {% if field.errors %}has-error has-feedback{% endif %}">
|
||||||
|
<label for="input_{{ field.name }}" class="col-sm-4 control-label">
|
||||||
|
{{ field.label }}
|
||||||
|
</label>
|
||||||
|
<div class="col-sm-8">
|
||||||
|
<input type="{{ field.field.widget.input_type }}"
|
||||||
|
class="form-control"
|
||||||
|
id="input_{{ field.name }}"
|
||||||
|
name="{{ field.html_name }}"
|
||||||
|
value="{% if field.field.widget.input_type != "password" and field.value %}{{ field.value }}{% endif %}">
|
||||||
|
{% if field.errors %}
|
||||||
|
<span class="glyphicon glyphicon-remove form-control-feedback"></span>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="col-sm-12 text-right">
|
||||||
|
<button type="submit"
|
||||||
|
class="btn btn-primary">
|
||||||
|
{% trans "Register" %}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1 @@
|
||||||
|
{% extends "_layout.html" %}
|
|
@ -0,0 +1,20 @@
|
||||||
|
{% extends "faq/layout.html" %}
|
||||||
|
|
||||||
|
{% block main_content %}
|
||||||
|
<div class="container">
|
||||||
|
<h1>FAQs</h1>
|
||||||
|
{% for cat in categories %}
|
||||||
|
<h3>{{ cat.name }}</h3>
|
||||||
|
<ul class="media-list">
|
||||||
|
{% for item in cat.questions.all %}
|
||||||
|
<li class="media well">
|
||||||
|
<div class="media-body">
|
||||||
|
<h2 class="media-heading">{{ item.title }}</h2>
|
||||||
|
<p>{{ item.answer|linebreaks }}</p>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
|
@ -13,7 +13,7 @@
|
||||||
<div class="row">
|
<div class="row">
|
||||||
{% for volume in FUTURE_RELEASES %}
|
{% for volume in FUTURE_RELEASES %}
|
||||||
<div class="col-sm-6 latest-manga">
|
<div class="col-sm-6 latest-manga">
|
||||||
{% include "manga/series/includes/volume.html" with volume=volume user=user show_publisher=True type='slim' %}
|
{% include "manga/series/includes/volume.html" with volume=volume user=user show_publisher=True show_language=True type='slim' %}
|
||||||
</div>
|
</div>
|
||||||
{% if forloop.counter|divisibleby:2 %}
|
{% if forloop.counter|divisibleby:2 %}
|
||||||
</div><div class="row">
|
</div><div class="row">
|
||||||
|
@ -28,7 +28,7 @@
|
||||||
<div class="row">
|
<div class="row">
|
||||||
{% for volume in LATEST_MANGA_ADDED %}
|
{% for volume in LATEST_MANGA_ADDED %}
|
||||||
<div class="col-sm-6 latest-manga">
|
<div class="col-sm-6 latest-manga">
|
||||||
{% include "manga/series/includes/volume.html" with volume=volume user=user show_publisher=True type='slim' %}
|
{% include "manga/series/includes/volume.html" with volume=volume user=user show_publisher=True show_language=True type='slim' %}
|
||||||
</div>
|
</div>
|
||||||
{% if forloop.counter|divisibleby:2 %}
|
{% if forloop.counter|divisibleby:2 %}
|
||||||
</div><div class="row">
|
</div><div class="row">
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
<p>¡Hola {{ user.username }}!</p>
|
||||||
|
|
||||||
|
<p>Ahora formas parte de una comunidad creciente de coleccionistas de comics, esperamos que te sientas a gusto y que nos ayudes a todos a mejorarla y sobretodo que sea útil para ti.</p>
|
||||||
|
|
||||||
|
<p><a href="http://shelfzilla.com">Entrar en Shelfzilla</a></p>
|
||||||
|
|
||||||
|
<p>Un saludo,<br />
|
||||||
|
el equipo.</p>
|
|
@ -19,7 +19,12 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if type == 'slim' %}
|
{% if type == 'slim' %}
|
||||||
<a href="{{ volume.series.get_absolute_url }}" data-pjax>
|
<a href="{{ volume.series.get_absolute_url }}" data-pjax>
|
||||||
<h4 class="media-heading">{{ volume }}</h4>
|
<h4 class="media-heading">
|
||||||
|
{% if show_language and volume.language %}
|
||||||
|
<img src="{% static "images/flags/"|add:volume.language.code|add:'.gif' code %}" />
|
||||||
|
{% endif %}
|
||||||
|
{{ volume }}
|
||||||
|
</h4>
|
||||||
</a>
|
</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="volume-number">
|
<div class="volume-number">
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
{% extends '_layout.html' %}
|
{% extends '_layout.html' %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block navigation_bar %}{% endblock %}
|
|
||||||
{% block page_title %}{{ block.super }} | Login{% endblock %}
|
{% block page_title %}{{ block.super }} | Login{% endblock %}
|
||||||
|
|
||||||
{% block extra_js %}
|
{% block extra_js %}
|
||||||
|
@ -19,7 +18,11 @@ $(function(){
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block main_content %}
|
{% block main_content %}
|
||||||
<div class="panel panel-primary panel-login">
|
<div class="container">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-3"></div>
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<div class="panel panel-primary">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<h3 class="panel-title">{% trans "Access the site" %}</h3>
|
<h3 class="panel-title">{% trans "Access the site" %}</h3>
|
||||||
</div>
|
</div>
|
||||||
|
@ -38,8 +41,17 @@ $(function(){
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
<div class="text-center">
|
||||||
<button class="btn btn-primary" type="submit">{% trans "Login" %}</button>
|
<button class="btn btn-primary" type="submit">{% trans "Login" %}</button>
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
<hr />
|
||||||
|
<div class="text-center">
|
||||||
|
<a href="{% url 'register' %}">¿No tienes cuenta? Regístrate aquí</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -14,6 +14,7 @@ urlpatterns = patterns(
|
||||||
url(r'^$', include('shelfzilla.apps.homepage.urls')),
|
url(r'^$', include('shelfzilla.apps.homepage.urls')),
|
||||||
url(r'^', include('shelfzilla.apps.landing.urls')),
|
url(r'^', include('shelfzilla.apps.landing.urls')),
|
||||||
url(r'^', include('shelfzilla.apps.account.urls')),
|
url(r'^', include('shelfzilla.apps.account.urls')),
|
||||||
|
url(r'^faqs/', include('shelfzilla.apps.faq.urls')),
|
||||||
url(r'^blog/', include('shelfzilla.apps.blog.urls', namespace='blog')),
|
url(r'^blog/', include('shelfzilla.apps.blog.urls', namespace='blog')),
|
||||||
url(r'^series/', include('shelfzilla.apps.manga.urls.series')),
|
url(r'^series/', include('shelfzilla.apps.manga.urls.series')),
|
||||||
url(r'^volumes/', include('shelfzilla.apps.manga.urls.volumes')),
|
url(r'^volumes/', include('shelfzilla.apps.manga.urls.volumes')),
|
||||||
|
@ -21,6 +22,14 @@ urlpatterns = patterns(
|
||||||
url(r'^search/', include('shelfzilla.apps.manga.urls.search')),
|
url(r'^search/', include('shelfzilla.apps.manga.urls.search')),
|
||||||
url(r'^_admin/', include('shelfzilla.apps._admin.urls')),
|
url(r'^_admin/', include('shelfzilla.apps._admin.urls')),
|
||||||
url(r'^admin/', include(admin.site.urls)),
|
url(r'^admin/', include(admin.site.urls)),
|
||||||
|
# url(r'^feedback/',
|
||||||
|
# include('object_feedback.urls', namespace="object_feedback")),
|
||||||
|
)
|
||||||
|
|
||||||
|
# API
|
||||||
|
urlpatterns += patterns(
|
||||||
|
'',
|
||||||
|
url(r'^api/v1/', include('shelfzilla.urls_api', namespace='api')),
|
||||||
)
|
)
|
||||||
|
|
||||||
if settings.DEBUG:
|
if settings.DEBUG:
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
# coding: utf-8
|
||||||
|
|
||||||
|
# django
|
||||||
|
from django.conf.urls import patterns, include, url
|
||||||
|
|
||||||
|
# app
|
||||||
|
from .views import BlockedView
|
||||||
|
|
||||||
|
|
||||||
|
# API
|
||||||
|
urlpatterns = patterns(
|
||||||
|
'',
|
||||||
|
# Manually blocked API endpoints
|
||||||
|
url(r'^auth/register/', BlockedView.as_view()),
|
||||||
|
# /auth
|
||||||
|
url(r'^auth/', include('djoser.urls')),
|
||||||
|
# /feed
|
||||||
|
url(r'^', include('shelfzilla.apps.account.api.urls')),
|
||||||
|
# /volumes
|
||||||
|
url(r'^', include('shelfzilla.apps.manga.api.urls')),
|
||||||
|
)
|
|
@ -1,9 +1,15 @@
|
||||||
|
# coding: utf-8
|
||||||
|
|
||||||
|
# python
|
||||||
import json
|
import json
|
||||||
|
|
||||||
|
# django
|
||||||
from django.views.generic import View as DjangoView
|
from django.views.generic import View as DjangoView
|
||||||
from django.template import RequestContext
|
from django.template import RequestContext
|
||||||
from django.shortcuts import render_to_response
|
from django.shortcuts import render_to_response
|
||||||
from django.http import HttpResponse
|
from django.http import HttpResponse
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
|
from django.core.exceptions import PermissionDenied
|
||||||
|
|
||||||
|
|
||||||
class View(DjangoView):
|
class View(DjangoView):
|
||||||
|
@ -46,3 +52,8 @@ class MessagesView(View):
|
||||||
)
|
)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
class BlockedView(View):
|
||||||
|
def dispatch(self, *args, **kwargs):
|
||||||
|
raise PermissionDenied
|
||||||
|
|
Reference in New Issue