parent
a3fbcbfece
commit
5ce8046928
631 changed files with 416 additions and 69438 deletions
@ -0,0 +1,34 @@ |
||||
# SITE SETTINGS |
||||
SITE_HOST=78.155.219.170 |
||||
USE_SSL=True |
||||
ALLOWED_HOSTS=78.155.219.170, |
||||
|
||||
# APP SETTINGS |
||||
SECRET_KEY=+fd(^upr^y9++w^k_p+2&k+^rtp5-um-pzvsrm9ycq++@_$5i* |
||||
|
||||
# DEBUG SETTINGS |
||||
DEBUG=False |
||||
DJANGO_DEBUG_TOOLBAR=False |
||||
|
||||
# DATABASE SETTINGS |
||||
DB_NAME=eshop_db |
||||
DB_USER=eshop_admin |
||||
DB_PASSWORD=12345678 |
||||
DB_HOST=localhost |
||||
DB_PORT=5432 |
||||
|
||||
# DATABASE PRODUCTION SETTINGS |
||||
DATABASE_URL=psql://eshop_admin:eshop_password@127.0.0.1:5432/eshop |
||||
|
||||
# EMAIL SETTINGS |
||||
EMAIL_BACKEND=djcelery_email.backends.CeleryEmailBackend |
||||
EMAIL_USE_TLS=True |
||||
EMAIL_USE_SSL=False |
||||
EMAIL_HOST=smtp.gmail.com |
||||
EMAIL_PORT=587 |
||||
EMAIL_HOST_USER=gmail_user |
||||
EMAIL_HOST_PASSWORD=gmail_password |
||||
|
||||
# CELERY SETTINGS |
||||
REDIS_CELERY_URL=redis://127.0.0.1 |
||||
|
||||
@ -1 +0,0 @@ |
||||
from .celery import app as celery_app |
||||
@ -1,10 +0,0 @@ |
||||
import os |
||||
from celery import Celery |
||||
from django.conf import settings |
||||
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'Eshop.settings') |
||||
|
||||
app = Celery('Eshop') |
||||
|
||||
app.config_from_object('django.conf:settings') |
||||
app.autodiscover_tasks(lambda: settings.INSTALLED_APPS) |
||||
Binary file not shown.
Binary file not shown.
@ -1,3 +0,0 @@ |
||||
from django.contrib import admin |
||||
|
||||
# Register your models here. |
||||
@ -1,5 +0,0 @@ |
||||
from django.apps import AppConfig |
||||
|
||||
|
||||
class CartConfig(AppConfig): |
||||
name = 'cart' |
||||
@ -1,86 +0,0 @@ |
||||
from decimal import Decimal |
||||
from django.conf import settings |
||||
from django.contrib import auth |
||||
from products.models import Product, Offer |
||||
# from discount.models import Discount |
||||
|
||||
class Cart(object): |
||||
def __init__(self, request): |
||||
self.session = request.session |
||||
self.discount_id = self.session.get('discount_id') |
||||
if request.user.is_authenticated(): |
||||
self.points = self.session.get('points') |
||||
self.points_quant = auth.get_user(request).profile.user_points |
||||
cart = self.session.get(settings.CART_SESSION_ID) |
||||
if not cart: |
||||
request.session['points'] = False |
||||
cart = self.session[settings.CART_SESSION_ID] = {} |
||||
self.cart = cart |
||||
|
||||
def add(self, offer, price_per_itom, quantity=1, update_quantity=False): |
||||
offer_slug = offer.slug |
||||
if offer_slug not in self.cart: |
||||
self.cart[offer_slug] = {'quantity': 0, |
||||
'price': str(price_per_itom)} |
||||
if update_quantity: |
||||
self.cart[offer_slug]['quantity'] = int(quantity) |
||||
else: |
||||
self.cart[offer_slug]['quantity'] += int(quantity) |
||||
self.save() |
||||
|
||||
def save(self): |
||||
self.session[settings.CART_SESSION_ID] = self.cart |
||||
self.session.modified = True |
||||
|
||||
def remove(self, offer_slug): |
||||
# product_id = str(product.id) |
||||
if offer_slug in self.cart: |
||||
del self.cart[offer_slug] |
||||
self.save() |
||||
|
||||
def __iter__(self): |
||||
offers_ids = self.cart.keys() |
||||
offers = Offer.objects.filter(slug__in=offers_ids) |
||||
|
||||
for offer in offers: |
||||
self.cart[str(offer.slug)]['offer'] = offer |
||||
|
||||
for item in self.cart.values(): |
||||
item['price'] = Decimal(item['price']) |
||||
item['total_price'] = item['price'] * item['quantity'] |
||||
yield item |
||||
|
||||
def __len__(self): |
||||
return sum(item['quantity'] for item in self.cart.values()) |
||||
|
||||
def get_total_price(self): |
||||
return sum(Decimal(item['price']) * item['quantity'] for item in self.cart.values()) |
||||
|
||||
def clear(self): |
||||
del self.session[settings.CART_SESSION_ID] |
||||
self.session.modified = True |
||||
|
||||
# @property |
||||
# def discount(self): |
||||
# if self.discount_id: |
||||
# return Discount.objects.get(id=self.discount_id) |
||||
# return None |
||||
|
||||
# def get_discount(self): |
||||
# if self.discount: |
||||
# return (self.discount.discount / Decimal('100')) * self.get_total_price() |
||||
# return Decimal('0') |
||||
|
||||
# def get_total_price_after_discount(self): |
||||
# return self.get_total_price() - self.get_discount() |
||||
|
||||
def get_total_deduct_points(self): |
||||
total_price = self.get_total_price() |
||||
print(total_price, self.points_quant) |
||||
if total_price <= self.points_quant: |
||||
print('Less') |
||||
self.points_quant = self.points_quant - total_price + 1 |
||||
return 1 |
||||
print('More') |
||||
return total_price - self.points_quant |
||||
|
||||
@ -1,6 +0,0 @@ |
||||
from .cart import Cart |
||||
|
||||
|
||||
def cart(request): |
||||
return {'cart': Cart(request)} |
||||
|
||||
@ -1,22 +0,0 @@ |
||||
from django import forms |
||||
|
||||
#PRODUCT_QUANTITY_CHOICES = [(i, str(i)) for i in range(1, 21)] |
||||
|
||||
class CartAddProductForm(forms.Form): |
||||
#quantity = forms.TypedChoiceField(choices=PRODUCT_QUANTITY_CHOICES, coerce=int) |
||||
quantity = forms.CharField(required=True, widget=forms.TextInput(attrs={ |
||||
'id': 'quantity', |
||||
'name': 'quantity', |
||||
'type': 'number', |
||||
'value': '0', |
||||
'onchange': 'calculate()'})) |
||||
product_slug = forms.CharField(label="product_slug", widget=forms.TextInput(attrs={ |
||||
'id': 'product_slug', |
||||
'name': 'product_slug', |
||||
'type': 'hidden'})) |
||||
price_per_itom = forms.IntegerField(label="price_per_itom", widget=forms.TextInput(attrs={ |
||||
'id': 'price_per_itom', |
||||
'name': 'price_per_itom', |
||||
'type': 'hidden'})) |
||||
update = forms.BooleanField(required=False, initial=False, widget=forms.HiddenInput) |
||||
|
||||
@ -1,3 +0,0 @@ |
||||
from django.db import models |
||||
|
||||
# Create your models here. |
||||
@ -1,3 +0,0 @@ |
||||
from django.test import TestCase |
||||
|
||||
# Create your tests here. |
||||
@ -1,8 +0,0 @@ |
||||
from django.conf.urls import url |
||||
from . import views |
||||
|
||||
urlpatterns = [ |
||||
url(r'^$', views.CartDetail, name='CartDetail'), |
||||
url(r'^remove/(?P<offer_slug>[-\w]+)/$', views.CartRemove, name='CartRemove'), |
||||
url(r'^add/$', views.CartAdd, name='CartAdd'), |
||||
] |
||||
@ -1,41 +0,0 @@ |
||||
from django.shortcuts import render, redirect, get_object_or_404 |
||||
from django.views.decorators.http import require_POST |
||||
from django.views.decorators.csrf import csrf_exempt |
||||
from django.contrib import auth |
||||
from products.models import Product, Offer |
||||
from .cart import Cart |
||||
from .forms import CartAddProductForm |
||||
# from discount.forms import DiscountApllyForm |
||||
|
||||
@csrf_exempt |
||||
@require_POST |
||||
def CartAdd(request): |
||||
cart = Cart(request) |
||||
form = CartAddProductForm(request.POST) |
||||
if form.is_valid(): |
||||
cd = form.cleaned_data |
||||
offer = get_object_or_404(Offer, slug=cd['product_slug']) |
||||
cart.add(offer=offer, price_per_itom=cd['price_per_itom'], quantity=cd['quantity'], |
||||
update_quantity=cd['update']) |
||||
return redirect('cart:CartDetail') |
||||
|
||||
def CartRemove(request, offer_slug): |
||||
cart = Cart(request) |
||||
# offer = get_object_or_404(Offer, slug=offer_slug) |
||||
cart.remove(offer_slug) |
||||
return redirect('cart:CartDetail') |
||||
|
||||
def CartDetail(request, points=False): |
||||
user = auth.get_user(request) |
||||
cart = Cart(request) |
||||
for item in cart: |
||||
item['update_quantity_form'] = CartAddProductForm( |
||||
initial={ |
||||
'quantity': item['quantity'], |
||||
'product_slug': item['offer'].slug, |
||||
'price_per_itom': item['price'], |
||||
'update': True |
||||
}) |
||||
# discount_apply_form = DiscountApllyForm() |
||||
return render(request, 'cart/detail.html', {'username': user.username, 'points': points}) |
||||
# 'discount_apply_form': discount_apply_form}) |
||||
@ -1,10 +0,0 @@ |
||||
from django.contrib import admin |
||||
from .models import Discount |
||||
|
||||
|
||||
class DiscountAdmin(admin.ModelAdmin): |
||||
list_display = ['code', 'valid_from', 'valid_to', 'discount', 'active'] |
||||
list_filter = ['valid_from', 'valid_to', 'active'] |
||||
search_field = ['code'] |
||||
|
||||
admin.site.register(Discount, DiscountAdmin) |
||||
@ -1,5 +0,0 @@ |
||||
from django.apps import AppConfig |
||||
|
||||
|
||||
class DiscountConfig(AppConfig): |
||||
name = 'discount' |
||||
@ -1,4 +0,0 @@ |
||||
from django import forms |
||||
|
||||
class DiscountApllyForm(forms.Form): |
||||
code = forms.CharField() |
||||
@ -1,26 +0,0 @@ |
||||
from django.db import models |
||||
import uuid |
||||
from django.db.models.signals import post_save |
||||
from datetime import datetime, timedelta |
||||
from django.core.validators import MinValueValidator, MaxValueValidator |
||||
from django.contrib.auth.models import User |
||||
|
||||
class Discount(models.Model): |
||||
user = models.OneToOneField(User, on_delete=models.CASCADE, null=True) |
||||
code = models.CharField(max_length=50, blank=True, unique=True, default=str(uuid.uuid4())) |
||||
valid_from = models.DateTimeField(default=datetime.now, blank=True) |
||||
valid_to = models.DateTimeField(default=datetime.now()+timedelta(days=7), blank=True) |
||||
discount = models.IntegerField(validators=[MinValueValidator(0), MaxValueValidator(100)], default=10) |
||||
active = models.BooleanField(default=True) |
||||
|
||||
def __str__(self): |
||||
return self.code |
||||
|
||||
def create_discount(sender, **kwargs): |
||||
if kwargs['created']: |
||||
user_discount = Discount.objects.create(user=kwargs['instance']) |
||||
|
||||
# post_save.connect(create_discount, sender=User) |
||||
|
||||
User.discount = property(lambda u: Discount.objects.get_or_create(user=u)[0]) |
||||
|
||||
@ -1,3 +0,0 @@ |
||||
from django.test import TestCase |
||||
|
||||
# Create your tests here. |
||||
@ -1,9 +0,0 @@ |
||||
from django.conf.urls import url |
||||
from . import views |
||||
|
||||
|
||||
urlpatterns = [ |
||||
url(r'^apply', views.DiscountApply, name='apply'), |
||||
url(r'^create', views.CreateDiscount, name='create'), |
||||
url(r'^points', views.PointsApply, name='points') |
||||
] |
||||
@ -1,47 +0,0 @@ |
||||
import uuid |
||||
from datetime import datetime |
||||
from django.shortcuts import render, redirect |
||||
from django.views.decorators.csrf import csrf_exempt |
||||
from datetime import datetime, timedelta |
||||
from django.contrib import auth |
||||
from django.views.decorators.http import require_POST |
||||
from django.contrib.auth.decorators import login_required |
||||
from .models import Discount |
||||
from .forms import DiscountApllyForm |
||||
|
||||
@login_required |
||||
@require_POST |
||||
@csrf_exempt |
||||
def PointsApply(request): |
||||
# request.session['points'] = True |
||||
return redirect('cart:CartDetail', points=True) |
||||
|
||||
@require_POST |
||||
def DiscountApply(request): |
||||
now = datetime.now() |
||||
form = DiscountApllyForm(request.POST) |
||||
if form.is_valid(): |
||||
code = form.cleaned_data['code'] |
||||
try: |
||||
discount = Discount.objects.get(code__iexact=code, |
||||
valid_from__lte=now, |
||||
valid_to__gte=now, |
||||
active=True) |
||||
request.session['discount_id'] = discount.id |
||||
except Discount.DoesNotExist: |
||||
request.session['discount_id'] = None |
||||
|
||||
return redirect('cart:CartDetail') |
||||
|
||||
@login_required |
||||
@require_POST |
||||
@csrf_exempt |
||||
def CreateDiscount(request): |
||||
user = auth.get_user(request) |
||||
Discount.objects.update_or_create(user=user, defaults={'code': str(uuid.uuid4()), 'valid_from': datetime.now(), |
||||
'valid_to': datetime.now()+timedelta(days=7), 'active': True}) |
||||
return redirect('profile:user_profile') |
||||
|
||||
|
||||
|
||||
|
||||
@ -0,0 +1,3 @@ |
||||
from .celery import app as celery_app |
||||
|
||||
__all__ = ['celery_app'] |
||||
@ -0,0 +1,10 @@ |
||||
import os |
||||
from celery import Celery |
||||
from django.conf import settings |
||||
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'eshop_project.settings.celery') |
||||
|
||||
app = Celery('eshop_project') |
||||
|
||||
app.config_from_object('django.conf:settings') |
||||
app.autodiscover_tasks(lambda: settings.INSTALLED_APPS) |
||||
@ -0,0 +1,178 @@ |
||||
[ |
||||
{ |
||||
"model": "contenttypes.contenttype", |
||||
"pk": 1, |
||||
"fields": { |
||||
"app_label": "admin", |
||||
"model": "logentry" |
||||
} |
||||
}, |
||||
{ |
||||
"model": "contenttypes.contenttype", |
||||
"pk": 2, |
||||
"fields": { |
||||
"app_label": "auth", |
||||
"model": "group" |
||||
} |
||||
}, |
||||
{ |
||||
"model": "contenttypes.contenttype", |
||||
"pk": 3, |
||||
"fields": { |
||||
"app_label": "auth", |
||||
"model": "permission" |
||||
} |
||||
}, |
||||
{ |
||||
"model": "contenttypes.contenttype", |
||||
"pk": 4, |
||||
"fields": { |
||||
"app_label": "auth", |
||||
"model": "user" |
||||
} |
||||
}, |
||||
{ |
||||
"model": "contenttypes.contenttype", |
||||
"pk": 5, |
||||
"fields": { |
||||
"app_label": "contenttypes", |
||||
"model": "contenttype" |
||||
} |
||||
}, |
||||
{ |
||||
"model": "contenttypes.contenttype", |
||||
"pk": 6, |
||||
"fields": { |
||||
"app_label": "sessions", |
||||
"model": "session" |
||||
} |
||||
}, |
||||
{ |
||||
"model": "contenttypes.contenttype", |
||||
"pk": 7, |
||||
"fields": { |
||||
"app_label": "landing", |
||||
"model": "subscriber" |
||||
} |
||||
}, |
||||
{ |
||||
"model": "contenttypes.contenttype", |
||||
"pk": 8, |
||||
"fields": { |
||||
"app_label": "orders", |
||||
"model": "order" |
||||
} |
||||
}, |
||||
{ |
||||
"model": "contenttypes.contenttype", |
||||
"pk": 9, |
||||
"fields": { |
||||
"app_label": "orders", |
||||
"model": "productsinbasket" |
||||
} |
||||
}, |
||||
{ |
||||
"model": "contenttypes.contenttype", |
||||
"pk": 10, |
||||
"fields": { |
||||
"app_label": "orders", |
||||
"model": "status" |
||||
} |
||||
}, |
||||
{ |
||||
"model": "contenttypes.contenttype", |
||||
"pk": 11, |
||||
"fields": { |
||||
"app_label": "orders", |
||||
"model": "productsinorder" |
||||
} |
||||
}, |
||||
{ |
||||
"model": "contenttypes.contenttype", |
||||
"pk": 12, |
||||
"fields": { |
||||
"app_label": "userprofile", |
||||
"model": "userprofile" |
||||
} |
||||
}, |
||||
{ |
||||
"model": "contenttypes.contenttype", |
||||
"pk": 13, |
||||
"fields": { |
||||
"app_label": "products", |
||||
"model": "productclass" |
||||
} |
||||
}, |
||||
{ |
||||
"model": "contenttypes.contenttype", |
||||
"pk": 14, |
||||
"fields": { |
||||
"app_label": "products", |
||||
"model": "productcategory" |
||||
} |
||||
}, |
||||
{ |
||||
"model": "contenttypes.contenttype", |
||||
"pk": 15, |
||||
"fields": { |
||||
"app_label": "products", |
||||
"model": "product" |
||||
} |
||||
}, |
||||
{ |
||||
"model": "contenttypes.contenttype", |
||||
"pk": 16, |
||||
"fields": { |
||||
"app_label": "products", |
||||
"model": "productimage" |
||||
} |
||||
}, |
||||
{ |
||||
"model": "contenttypes.contenttype", |
||||
"pk": 17, |
||||
"fields": { |
||||
"app_label": "products", |
||||
"model": "productattribute" |
||||
} |
||||
}, |
||||
{ |
||||
"model": "contenttypes.contenttype", |
||||
"pk": 18, |
||||
"fields": { |
||||
"app_label": "products", |
||||
"model": "offer" |
||||
} |
||||
}, |
||||
{ |
||||
"model": "contenttypes.contenttype", |
||||
"pk": 19, |
||||
"fields": { |
||||
"app_label": "products", |
||||
"model": "attributechoicevalue" |
||||
} |
||||
}, |
||||
{ |
||||
"model": "contenttypes.contenttype", |
||||
"pk": 20, |
||||
"fields": { |
||||
"app_label": "ipn", |
||||
"model": "paypalipn" |
||||
} |
||||
}, |
||||
{ |
||||
"model": "contenttypes.contenttype", |
||||
"pk": 21, |
||||
"fields": { |
||||
"app_label": "discount", |
||||
"model": "discount" |
||||
} |
||||
}, |
||||
{ |
||||
"model": "contenttypes.contenttype", |
||||
"pk": 22, |
||||
"fields": { |
||||
"app_label": "userprofile", |
||||
"model": "pickuprequest" |
||||
} |
||||
} |
||||
] |
||||
@ -0,0 +1,7 @@ |
||||
from .base import * |
||||
|
||||
CELERY_BROKER_URL= env.str('CELERY_BROKER_URL') |
||||
CELERY_RESULT_BACKEND = env.str('CELERY_RESULT_BACKEND') |
||||
CELERY_ACCEPT_CONTENT = tuple(env.list("CELERY_ACCEPT_CONTENT")) |
||||
CELERY_RESULT_SERIALIZER = env.str('json') |
||||
CELERY_TASK_SERIALIZER = env.str('json') |
||||
@ -0,0 +1,16 @@ |
||||
from .base import * |
||||
|
||||
DATABASES = { |
||||
**DATABASES, |
||||
'default': { |
||||
'ENGINE': 'django.db.backends.postgresql_psycopg2', |
||||
'NAME': env.str('DB_NAME'), |
||||
'USER': env.str('DB_USER'), |
||||
'PASSWORD': env.str('DB_PASSWORD'), |
||||
'HOST': env.str('DB_HOST'), |
||||
'PORT': env.str('DB_PORT') |
||||
} |
||||
} |
||||
|
||||
EMAIL_BACKEND = 'djcelery_email.backends.CeleryEmailBackend' |
||||
|
||||
@ -0,0 +1,15 @@ |
||||
import environ |
||||
|
||||
__all__ = ( |
||||
'env', |
||||
) |
||||
|
||||
env = environ.Env() |
||||
|
||||
|
||||
env.read_env( |
||||
env.path( |
||||
'ENV_FILE_PATH', |
||||
default=(environ.Path(__file__) - 3).path('.env')() |
||||
)() |
||||
) |
||||
@ -0,0 +1,24 @@ |
||||
from .base import * |
||||
from .env import env |
||||
|
||||
# Database settings. There must a database url |
||||
DATABASES += { |
||||
'default': env.db() |
||||
} |
||||
|
||||
# Email backend settings |
||||
EMAIL_BACKEND = env.str('EMAIL_BACKEND') |
||||
EMAIL_USE_TLS = env.bool('EMAIL_USE_TLS') |
||||
EMAIL_USE_SSL = env.bool("EMAIL_USE_SSL") |
||||
EMAIL_HOST = env.str('EMAIL_HOST') |
||||
EMAIL_PORT = env.int('EMAIL_PORT') |
||||
EMAIL_HOST_USER = env.str('EMAIL_HOST_USER') |
||||
EMAIL_HOST_PASSWORD = env.str('EMAIL_HOST_PASSWORD') |
||||
|
||||
# Email user settings |
||||
ADMINS = ( |
||||
('Dmitriy Belousov', 'dimkasp@mail.ru'), |
||||
) |
||||
|
||||
MANAGERS = ADMINS |
||||
DEFAULT_FROM_EMAIL = 'notreply@russianprograms' |
||||
@ -0,0 +1 @@ |
||||
__all__ = () |
||||
@ -0,0 +1,26 @@ |
||||
""" |
||||
Two things are wrong with Django's default `SECRET_KEY` system: |
||||
1. It is not random but pseudo-random |
||||
2. It saves and displays the SECRET_KEY in `settings.py` |
||||
This snippet |
||||
1. uses `SystemRandom()` instead to generate a random key |
||||
2. saves a local `secret.txt` |
||||
The result is a random and safely hidden `SECRET_KEY`. |
||||
""" |
||||
try: |
||||
SECRET_KEY |
||||
except NameError as ne: |
||||
import os |
||||
from eshop_project.settings.base import BASE_DIR |
||||
SECRET_FILE = os.path.join(BASE_DIR, 'secret.txt') |
||||
try: |
||||
SECRET_KEY = open(SECRET_FILE).read().strip() |
||||
except IOError: |
||||
try: |
||||
import random |
||||
SECRET_KEY = ''.join([random.SystemRandom().choice('abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*(-_=+)') for i in range(50)]) |
||||
with open(SECRET_FILE,'w') as f: |
||||
f.write(SECRET_KEY) |
||||
except IOError: |
||||
Exception('Please create a %s file with random characters \ |
||||
to generate your secret key!' % SECRET_FILE) |
||||
File diff suppressed because it is too large
Load Diff
@ -1,15 +0,0 @@ |
||||
from django.contrib import admin |
||||
from .models import * |
||||
|
||||
# Register your models here. |
||||
|
||||
class SubscriberAdmin(admin.ModelAdmin): |
||||
|
||||
list_display = [field.name for field in Subscriber._meta.fields] |
||||
list_filter = ['name'] |
||||
search_fields = ['name', 'email'] |
||||
|
||||
class Meta: |
||||
model = Subscriber |
||||
|
||||
admin.site.register(Subscriber, SubscriberAdmin) |
||||
@ -1,5 +0,0 @@ |
||||
from django.apps import AppConfig |
||||
|
||||
|
||||
class LandingConfig(AppConfig): |
||||
name = 'landing' |
||||
@ -1,8 +0,0 @@ |
||||
from django import forms |
||||
from .models import * |
||||
|
||||
class SubscriberForm(forms.ModelForm): |
||||
|
||||
class Meta: |
||||
model = Subscriber |
||||
exclude = [""] |
||||
@ -1,16 +0,0 @@ |
||||
from django.db import models |
||||
|
||||
# Create your models here. |
||||
class Subscriber(models.Model): |
||||
email = models.EmailField() |
||||
name = models.CharField(max_length=128) |
||||
|
||||
class Meta: |
||||
verbose_name = 'MySubsciber' |
||||
verbose_name_plural = 'List of Subscribers' |
||||
|
||||
def __str__(self): |
||||
try: |
||||
return self.name |
||||
except: |
||||
return '{0!s}'.format(self.id) |
||||
@ -1,3 +0,0 @@ |
||||
from django.test import TestCase |
||||
|
||||
# Create your tests here. |
||||
@ -1,7 +0,0 @@ |
||||
from django.conf.urls import url |
||||
from . import views |
||||
|
||||
urlpatterns = [ |
||||
url(r'^landing/', views.landing, name='landing'), |
||||
#url(r'^$', views.home, name='home'), |
||||
] |
||||
@ -1,21 +0,0 @@ |
||||
from django.shortcuts import render |
||||
from .forms import SubscriberForm |
||||
from django.contrib import auth |
||||
from products.models import * |
||||
|
||||
def landing(request): |
||||
form = SubscriberForm(request.POST or None) |
||||
|
||||
if request.method == "POST" and form.is_valid(): |
||||
print(form.cleaned_data) |
||||
form.save() |
||||
|
||||
return render(request, 'landing/landing.html', locals()) |
||||
|
||||
|
||||
def home(request): |
||||
product_images = ProductImage.objects.filter(is_active=True, is_main=True, product__is_active=True) |
||||
product_images_phones = product_images.filter(product__category__id=1) |
||||
product_images_watches = product_images.filter(product__category__id=2) |
||||
username = auth.get_user(request).username |
||||
return render(request, 'landing/home.html', locals()) |
||||
@ -1,3 +0,0 @@ |
||||
from django.contrib import admin |
||||
|
||||
# Register your models here. |
||||
@ -1,5 +0,0 @@ |
||||
from django.apps import AppConfig |
||||
|
||||
|
||||
class LoginsysConfig(AppConfig): |
||||
name = 'loginsys' |
||||
@ -1,23 +0,0 @@ |
||||
from django import forms |
||||
from django.contrib.auth.models import User |
||||
from django.contrib.auth.forms import UserCreationForm |
||||
|
||||
class RegistrationForm(UserCreationForm): |
||||
email = forms.EmailField(required=True) |
||||
parent = forms.CharField(required = False) |
||||
|
||||
class Meta: |
||||
model = User |
||||
fields = ('username', 'email', 'password1', 'password2', 'parent') |
||||
|
||||
def save(self, commit=True): |
||||
user = super(UserCreationForm, self).save(commit=False) |
||||
user.email = self.cleaned_data['email'] |
||||
if self.cleaned_data.get('parent'): |
||||
user.parent = User.objects.get(username=self.cleaned_data['parent']) |
||||
user.set_password(self.cleaned_data['password1']) |
||||
|
||||
if commit: |
||||
user.save() |
||||
|
||||
return user |
||||
@ -1,2 +0,0 @@ |
||||
from django.db import models |
||||
|
||||
@ -1,3 +0,0 @@ |
||||
from django.test import TestCase |
||||
|
||||
# Create your tests here. |
||||
@ -1,24 +0,0 @@ |
||||
"""Eshop URL Configuration |
||||
|
||||
The `urlpatterns` list routes URLs to views. For more information please see: |
||||
https://docs.djangoproject.com/en/1.10/topics/http/urls/ |
||||
Examples: |
||||
Function views |
||||
1. Add an import: from my_app import views |
||||
2. Add a URL to urlpatterns: url(r'^$', views.home, name='home') |
||||
Class-based views |
||||
1. Add an import: from other_app.views import Home |
||||
2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home') |
||||
Including another URLconf |
||||
1. Import the include() function: from django.conf.urls import url, include |
||||
2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) |
||||
""" |
||||
from django.conf.urls import url |
||||
from . import views |
||||
|
||||
|
||||
urlpatterns = [ |
||||
url(r'^login/', views.login, name='login'), |
||||
url(r'^logout/', views.logout, name='logout'), |
||||
url(r'^register/', views.register, name='register'), |
||||
] |
||||
@ -1,44 +0,0 @@ |
||||
from django.shortcuts import render_to_response, redirect |
||||
from django.contrib import auth |
||||
from django.views.decorators.csrf import csrf_exempt |
||||
from .forms import RegistrationForm |
||||
|
||||
@csrf_exempt |
||||
def login(request): |
||||
args = {} |
||||
if request.POST: |
||||
username = request.POST.get('username', '') |
||||
password = request.POST.get('password', '') |
||||
user = auth.authenticate(username=username, password=password) |
||||
if user is not None: |
||||
auth.login(request, user) |
||||
return redirect('/') |
||||
else: |
||||
args['login_error'] = "User is not found" |
||||
return render_to_response('login/login.html', args) |
||||
|
||||
else: |
||||
return render_to_response('login/login.html', args) |
||||
|
||||
def logout(request): |
||||
auth.logout(request) |
||||
return redirect('/') |
||||
|
||||
@csrf_exempt |
||||
def register(request): |
||||
args= {} |
||||
args['form'] = RegistrationForm() |
||||
if request.POST: |
||||
newuser_form = RegistrationForm(request.POST) |
||||
if newuser_form.is_valid(): |
||||
newuser_form.save() |
||||
newuser = auth.authenticate(username=newuser_form.cleaned_data['username'], |
||||
password=newuser_form.cleaned_data['password1']) |
||||
auth.login(request, newuser) |
||||
return redirect('/') |
||||
else: |
||||
args['form'] = newuser_form |
||||
return render_to_response('login/register.html', args) |
||||
|
||||
|
||||
|
||||
@ -1,95 +0,0 @@ |
||||
from django.contrib import admin |
||||
from django.http import HttpResponse |
||||
from django.core.urlresolvers import reverse |
||||
from django.utils.html import format_html |
||||
from decimal import Decimal |
||||
import csv |
||||
import datetime |
||||
from django.contrib.auth.models import User |
||||
from userprofile.models import UserProfile |
||||
from .models import * |
||||
|
||||
def OrderDetail(obj): |
||||
return format_html('<a href="{}">View</a>'.format( |
||||
reverse('orders:AdminOrderDetail', args=[obj.id]) |
||||
)) |
||||
|
||||
def ExportToCSV(modeladmin, request, queryset): |
||||
opts = modeladmin.model._meta |
||||
response = HttpResponse(content_type='text/csv') |
||||
response['Content-Disposition'] = 'attachment; filename=Orders-{}.csv'.format(datetime.datetime.now().strftime("%d/%m/%Y")) |
||||
writer = csv.writer(response) |
||||
|
||||
fields = [field for field in opts.get_fields() if not field.many_to_many and not field.one_to_many] |
||||
|
||||
writer.writerow([field.verbose_name for field in fields]) |
||||
|
||||
for obj in queryset: |
||||
data_row = [] |
||||
for field in fields: |
||||
value = getattr(obj, field.name) |
||||
if isinstance(value, datetime.datetime): |
||||
value = value.strftime('%d/%m/%Y') |
||||
|
||||
data_row.append(value) |
||||
writer.writerow(data_row) |
||||
return response |
||||
ExportToCSV.short_description = 'Export CSV' |
||||
|
||||
def OrderPDF(obj): |
||||
return format_html('<a href="{}">PDF</a>'.format( |
||||
reverse('orders:AdminOrderPDF', args=[obj.id]) |
||||
)) |
||||
OrderPDF.short_description = 'In PDF format' |
||||
|
||||
class ProductsInOrderInline(admin.TabularInline): |
||||
model = ProductsInOrder |
||||
extra = 0 |
||||
|
||||
class StatusAdmin(admin.ModelAdmin): |
||||
list_display = [field.name for field in Status._meta.fields] |
||||
|
||||
class Meta: |
||||
model = Status |
||||
|
||||
def delete_model(modeladmin, request, queryset): |
||||
for obj in queryset: |
||||
print(obj.user) |
||||
user_profile = obj.user.profile |
||||
parent_profile = user_profile.parent.profile |
||||
parent_profile.user_points += round(obj.total_price * Decimal(0.05)) |
||||
parent_profile.save() |
||||
obj.delete() |
||||
delete_model.short_description = "Удалить как завершенные" |
||||
|
||||
class OrderAdmin (admin.ModelAdmin): |
||||
list_display = ['id', 'customer_name', 'customer_email', 'customer_phone', 'city', 'customer_address', |
||||
'paid', 'status', 'created', 'updated', OrderDetail, OrderPDF] |
||||
|
||||
list_filter = ['paid', 'created', 'updated'] |
||||
inlines = [ProductsInOrderInline] |
||||
actions = [ExportToCSV, delete_model] |
||||
|
||||
class Meta: |
||||
model = Order |
||||
|
||||
class ProductsInOrderAdmin(admin.ModelAdmin): |
||||
list_display = [field.name for field in ProductsInOrder._meta.fields] |
||||
|
||||
class Meta: |
||||
model = ProductsInOrder |
||||
|
||||
class ProductsInBasketAdmin(admin.ModelAdmin): |
||||
list_display = [field.name for field in ProductsInBasket._meta.fields] |
||||
|
||||
class Meta: |
||||
model = ProductsInBasket |
||||
|
||||
|
||||
|
||||
|
||||
|
||||
admin.site.register(Status, StatusAdmin) |
||||
admin.site.register(Order, OrderAdmin) |
||||
admin.site.register(ProductsInOrder, ProductsInOrderAdmin) |
||||
admin.site.register(ProductsInBasket, ProductsInBasketAdmin) |
||||
@ -1,5 +0,0 @@ |
||||
from django.apps import AppConfig |
||||
|
||||
|
||||
class OrdersConfig(AppConfig): |
||||
name = 'orders' |
||||
@ -1,11 +0,0 @@ |
||||
from .models import ProductsInBasket |
||||
|
||||
def getting_basket_info(request): |
||||
session_key = request.session.session_key |
||||
if not session_key: |
||||
request.session.cycle_key() |
||||
|
||||
products_in_basket = ProductsInBasket.objects.filter(session_key=session_key, is_active=True) |
||||
products_total_nmb = products_in_basket.count() |
||||
|
||||
return locals() |
||||
@ -1,15 +0,0 @@ |
||||
from django import forms |
||||
from phonenumber_field.formfields import PhoneNumberField |
||||
from .models import Order |
||||
|
||||
class OrderCreateForm(forms.ModelForm): |
||||
|
||||
customer_name = forms.CharField(max_length=64, required=True, help_text='Введите Ваше полное Ф.И.О') |
||||
customer_phone = PhoneNumberField(required=True, help_text='Введите Ваш номер телефона') |
||||
customer_email = forms.EmailField(required=True, help_text='Введите Ваш e-mail') |
||||
city = forms.CharField(max_length=100, help_text='Введите Ваш город') |
||||
|
||||
class Meta: |
||||
model = Order |
||||
fields = ['customer_name', 'customer_email', 'customer_phone', 'city'] |
||||
|
||||
@ -1,112 +0,0 @@ |
||||
from django.db import models |
||||
from django.db.models.signals import post_save |
||||
from django.contrib.auth.models import User |
||||
from django.dispatch import receiver |
||||
from phonenumber_field.modelfields import PhoneNumberField |
||||
# from discount.models import Discount |
||||
from decimal import Decimal |
||||
from django.core.validators import MinValueValidator, MaxValueValidator |
||||
from products.models import Product, Offer |
||||
|
||||
|
||||
class Status(models.Model): |
||||
name = models.CharField(max_length=16, blank=True, null=True, default=None) |
||||
is_active = models.BooleanField(default=True) |
||||
created = models.DateField(auto_now_add=True, auto_now=False) |
||||
updated = models.DateField(auto_now_add=False, auto_now=True) |
||||
|
||||
|
||||
def __str__(self): |
||||
return self.name |
||||
|
||||
class Meta: |
||||
verbose_name = 'State of order' |
||||
verbose_name_plural = 'States' |
||||
|
||||
class Order(models.Model): |
||||
user = models.ForeignKey(User, blank=True, null=True, default=None) |
||||
total_price = models.DecimalField(max_digits=10, decimal_places=2, default=0) |
||||
customer_name = models.CharField(max_length=64, blank=True, null=True, default=None) |
||||
customer_email = models.EmailField(blank=True, null=True, default=None) |
||||
customer_phone = PhoneNumberField(blank=True, null=True, default=None) |
||||
city = models.CharField(max_length=100, blank=True, null=True, default=None) |
||||
customer_address = models.CharField(max_length=128, blank=True, null=True, default=None) |
||||
comment = models.TextField(blank=True, null=True, default=None) |
||||
status = models.ForeignKey(Status, blank=True, null=True, default=None) |
||||
created = models.DateField(auto_now_add=True, auto_now=False) |
||||
updated = models.DateField(auto_now_add=False, auto_now=True) |
||||
paid = models.BooleanField(default=False) |
||||
# discount = models.ForeignKey(Discount, related_name='orders', null=True, blank=True) |
||||
# discount_value = models.IntegerField(default=0, validators=[MinValueValidator(0), MaxValueValidator(100)]) |
||||
points_quant = models.IntegerField(default=0) |
||||
|
||||
def __str__(self): |
||||
return "Order {!s} has status {}: ".format(self.id, self.status) |
||||
|
||||
class Meta: |
||||
ordering = ('-created',) |
||||
verbose_name = 'Order' |
||||
verbose_name_plural = 'Orders' |
||||
|
||||
def save(self, *args, **kwargs): |
||||
super(Order, self).save(*args, **kwargs) |
||||
|
||||
|
||||
class ProductsInOrder(models.Model): |
||||
order = models.ForeignKey(Order, blank=True, null=True, default=None, related_name='items') |
||||
product = models.ForeignKey(Offer, blank=True, null=True, default=None) |
||||
number = models.PositiveIntegerField(default=1) |
||||
price_per_itom = models.DecimalField(max_digits=10, decimal_places=2, default=0) |
||||
total_price = models.DecimalField(max_digits=10, decimal_places=2, default=0) |
||||
is_active = models.BooleanField(default=True) |
||||
created = models.DateField(auto_now_add=True, auto_now=False) |
||||
updated = models.DateField(auto_now_add=False, auto_now=True) |
||||
|
||||
def __str__(self): |
||||
return self.product.name |
||||
|
||||
class Meta: |
||||
verbose_name = 'Product in Order' |
||||
verbose_name_plural = 'Products in Order' |
||||
|
||||
def save(self, *args, **kwargs): |
||||
# self.price_per_itom = self.product.price |
||||
self.total_price = self.number * self.price_per_itom |
||||
super(ProductsInOrder, self).save(*args, **kwargs) |
||||
|
||||
class ProductsInBasket(models.Model): |
||||
session_key = models.CharField(max_length=128, blank=True, null=True, default=None) |
||||
order = models.ForeignKey(Order, blank=True, null=True, default=None) |
||||
product = models.ForeignKey(Product, blank=True, null=True, default=None) |
||||
number = models.IntegerField(default=1) |
||||
price_per_itom = models.DecimalField(max_digits=10, decimal_places=2, default=0) |
||||
total_price = models.DecimalField(max_digits=10, decimal_places=2, default=0) |
||||
is_active = models.BooleanField(default=True) |
||||
created = models.DateField(auto_now_add=True, auto_now=False) |
||||
updated = models.DateField(auto_now_add=False, auto_now=True) |
||||
|
||||
def __str__(self): |
||||
return self.product.name |
||||
|
||||
class Meta: |
||||
verbose_name = 'Product in Cart' |
||||
verbose_name_plural = 'Products in Cart' |
||||
|
||||
def save(self, *args, **kwargs): |
||||
self.price_per_itom = self.product.price |
||||
self.total_price = int(self.number) * self.price_per_itom |
||||
super(ProductsInBasket, self).save(*args, **kwargs) |
||||
|
||||
@receiver(post_save, sender=ProductsInOrder) |
||||
def product_in_order_post_save(instance,**kwargs): |
||||
order = instance.order |
||||
all_products_in_order = ProductsInOrder.objects.filter(order=order, is_active=True) |
||||
|
||||
order_total_price = sum(item.total_price for item in all_products_in_order) |
||||
# if order.discount: |
||||
# order.total_price = order_total_price * (order.discount_value / Decimal('100')) |
||||
if order.points_quant: |
||||
order.total_price = order_total_price - order.points_quant |
||||
else: |
||||
order.total_price = order_total_price |
||||
order.save(force_update=True) |
||||
@ -1,43 +0,0 @@ |
||||
from django.conf import settings |
||||
from celery import task |
||||
from django.template.loader import render_to_string |
||||
from django.core.mail import send_mail, EmailMessage |
||||
from io import BytesIO |
||||
import weasyprint |
||||
import pytils |
||||
from .models import Order |
||||
|
||||
SUPPLIER_INFO = '''ООО "Русские Программы", ИНН 7713409230, КПП 771301001, |
||||
127411, Москва г, Дмитровское ш., дом № 157, корпус 7, тел.: +74957258950''' |
||||
|
||||
requisites = {'name': 'ООО "Русские Программы"', 'bank': 'АО "СМП БАНК" Г. МОСКВА', 'INN': '7713409230', |
||||
'KPP': '771301001', 'BIK': '44525503', 'bank_acc': '30101810545250000503', 'acc': '40702810300750000177', |
||||
'sup_info': SUPPLIER_INFO} |
||||
|
||||
@task |
||||
def OrderCreated(order_id): |
||||
""" |
||||
Sending Email of order creating |
||||
""" |
||||
order = Order.objects.get(id=order_id) |
||||
verb_price = pytils.numeral.in_words(round(order.total_price)) |
||||
verb_cur = pytils.numeral.choose_plural(round(order.total_price), ("рубль", "рубля", "рублей")) |
||||
subject = 'Order {}'.format(order.id) |
||||
message = 'Dear, {}, You have successfully placed an order.\ |
||||
Your order number {}'.format(order.customer_name, order.id) |
||||
mail_send = EmailMessage(subject, message, 'admin@myshop.ru', [order.customer_email, 'bda2291@mail.ru']) |
||||
|
||||
# html = render_to_string('orders:AdminOrderPDF', args=[order_id]) |
||||
|
||||
html = render_to_string('orders/pdf.html', {**requisites, 'order': order, |
||||
'verb_cur': verb_cur, 'verb_price': verb_price}) |
||||
rendered_html = html.encode(encoding="UTF-8") |
||||
out = BytesIO() |
||||
weasyprint.HTML(string=rendered_html).write_pdf(out, |
||||
stylesheets=[weasyprint.CSS(settings.STATIC_ROOT + 'css/bootstrap.min.css')]) |
||||
|
||||
# weasyprint.HTML(string=rendered_html, base_url=request.build_absolute_uri()).write_pdf(response, |
||||
# stylesheets=[weasyprint.CSS(settings.STATIC_ROOT + '/css/bootstrap.min.css')]) |
||||
mail_send.attach('order_{}.pdf'.format(order_id), out.getvalue(), 'application/pdf') |
||||
mail_send.send() |
||||
return mail_send |
||||
@ -1,3 +0,0 @@ |
||||
from django.test import TestCase |
||||
|
||||
# Create your tests here. |
||||
@ -1,25 +0,0 @@ |
||||
"""Eshop URL Configuration |
||||
|
||||
The `urlpatterns` list routes URLs to views. For more information please see: |
||||
https://docs.djangoproject.com/en/1.10/topics/http/urls/ |
||||
Examples: |
||||
Function views |
||||
1. Add an import: from my_app import views |
||||
2. Add a URL to urlpatterns: url(r'^$', views.home, name='home') |
||||
Class-based views |
||||
1. Add an import: from other_app.views import Home |
||||
2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home') |
||||
Including another URLconf |
||||
1. Import the include() function: from django.conf.urls import url, include |
||||
2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) |
||||
""" |
||||
from django.conf.urls import url |
||||
from . import views |
||||
|
||||
|
||||
urlpatterns = [ |
||||
url(r'^basket_adding/', views.basket_adding, name='basket_adding'), |
||||
url(r'^create/$', views.OrderCreate, name='OrderCreate'), |
||||
url(r'^admin/order/(?P<order_id>\d+)/$', views.AdminOrderDetail, name='AdminOrderDetail'), |
||||
url(r'^admin/order/(?P<order_id>\d+)/pdf/$', views.AdminOrderPDF, name='AdminOrderPDF') |
||||
] |
||||
@ -1,117 +0,0 @@ |
||||
from django.shortcuts import render, redirect, get_object_or_404, render_to_response |
||||
from django.conf import settings |
||||
from django.contrib import auth |
||||
from django.http import HttpResponse |
||||
from django.template.loader import render_to_string, get_template |
||||
import weasyprint |
||||
import pytils |
||||
from django.core.urlresolvers import reverse |
||||
from django.http import JsonResponse |
||||
from django.contrib.admin.views.decorators import staff_member_required |
||||
from .models import ProductsInBasket, ProductsInOrder, Order |
||||
from .forms import OrderCreateForm |
||||
from .tasks import OrderCreated |
||||
from cart.cart import Cart |
||||
|
||||
SUPPLIER_INFO = '''ООО "Русские Программы", ИНН 7713409230, КПП 771301001, |
||||
127411, Москва г, Дмитровское ш., дом № 157, корпус 7, тел.: +74957258950''' |
||||
|
||||
requisites = {'name': 'ООО "Русские Программы"', 'bank': 'АО "СМП БАНК" Г. МОСКВА', 'INN': '7713409230', |
||||
'KPP': '771301001', 'BIK': '44525503', 'bank_acc': '30101810545250000503', 'acc': '40702810300750000177', |
||||
'sup_info': SUPPLIER_INFO} |
||||
|
||||
def basket_adding(request): |
||||
return_dict = {} |
||||
session_key = request.session.session_key |
||||
data = request.POST |
||||
product_id = data.get("product_id") |
||||
nmb = data.get("nmb") |
||||
|
||||
new_product, created = ProductsInBasket.objects.get_or_create(session_key=session_key, product_id=product_id, defaults={'number':nmb}) |
||||
if not created: |
||||
new_product.number += int(nmb) |
||||
new_product.save(force_update=True) |
||||
|
||||
products_in_basket = ProductsInBasket.objects.filter(session_key=session_key, is_active=True) |
||||
products_total_nmb = products_in_basket.count() |
||||
return_dict["products_total_nmb"] = products_total_nmb |
||||
return_dict["products"] = [] |
||||
|
||||
for item in products_in_basket: |
||||
product_dict = {} |
||||
product_dict["id"] = item.id |
||||
product_dict["name"] = item.product.name |
||||
product_dict["price_per_item"] = item.price_per_itom |
||||
product_dict["nmb"] = item.number |
||||
return_dict["products"].append(product_dict) |
||||
|
||||
return JsonResponse(return_dict) |
||||
|
||||
|
||||
def basket_remove(request): |
||||
return_dict = {} |
||||
session_key = request.session.session_key |
||||
data = request.POST |
||||
product_id = data.get("product_id") |
||||
|
||||
|
||||
def OrderCreate(request): |
||||
cart = Cart(request) |
||||
user = auth.get_user(request) |
||||
profile = user.profile |
||||
if not user.username: |
||||
return redirect('auth:login') |
||||
if request.method == 'POST': |
||||
form = OrderCreateForm(request.POST) |
||||
if form.is_valid(): |
||||
order = form.save(commit=False) |
||||
order.user = user |
||||
# if cart.discount: |
||||
# order.discount = cart.discount |
||||
# order.discount_value = cart.discount.discount |
||||
|
||||
if cart.points: |
||||
print(cart.points_quant) |
||||
order.points_quant = cart.points_quant |
||||
profile.user_points -= cart.points_quant |
||||
profile.save() |
||||
order.save() |
||||
|
||||
for item in cart: |
||||
ProductsInOrder.objects.create(order=order, product=item['offer'], |
||||
price_per_itom=item['price'], |
||||
number=item['quantity']) |
||||
cart.clear() |
||||
|
||||
# Asinc mail sending |
||||
OrderCreated.delay(order.id) |
||||
request.session['order_id'] = order.id |
||||
|
||||
# return redirect(reverse('payment:process')) |
||||
return render(request, 'orders/created.html', {'username': user.username, 'order': order}) |
||||
else: |
||||
return render('orders/create.html', {'username': user.username, 'cart': cart, 'form': form}) |
||||
|
||||
form = OrderCreateForm(instance=profile) |
||||
return render(request, 'orders/create.html', {'username': user.username, 'cart': cart, 'form': form}) |
||||
|
||||
|
||||
@staff_member_required |
||||
def AdminOrderDetail(request, order_id): |
||||
order = get_object_or_404(Order, id=order_id) |
||||
return render(request, 'admin/orders/detail.html', {'order': order}) |
||||
|
||||
|
||||
@staff_member_required |
||||
def AdminOrderPDF(request, order_id): |
||||
order = get_object_or_404(Order, id=order_id) |
||||
verb_price = pytils.numeral.in_words(round(order.total_price)) |
||||
verb_cur = pytils.numeral.choose_plural(round(order.total_price), ("рубль", "рубля", "рублей")) |
||||
html = render_to_string('orders/pdf.html', {**requisites, 'order': order, |
||||
'verb_cur': verb_cur, 'verb_price': verb_price}) |
||||
rendered_html = html.encode(encoding="UTF-8") |
||||
response = HttpResponse(content_type='application/pdf') |
||||
response['Content-Disposition'] = 'filename=order_{}.pdf'.format(order.id) |
||||
weasyprint.HTML(string=rendered_html, base_url=request.build_absolute_uri()).write_pdf(response, |
||||
stylesheets=[weasyprint.CSS(settings.STATIC_ROOT + '/css/bootstrap.min.css')]) |
||||
return response |
||||
@ -1,5 +0,0 @@ |
||||
{ |
||||
"dependencies": { |
||||
"bower": "latest" |
||||
} |
||||
} |
||||
@ -1,206 +0,0 @@ |
||||
from django.contrib import admin |
||||
# from mptt.admin import MPTTModelAdmin |
||||
from import_export import resources, fields, widgets |
||||
from import_export.admin import ImportExportModelAdmin |
||||
from .models import * |
||||
|
||||
class CustomModelResource(resources.ModelResource): |
||||
def before_import_row(self, row, **kwargs): |
||||
""" |
||||
Override to add additional logic. Does nothing by default. |
||||
""" |
||||
try: |
||||
row['attributes'] = eval(row['attributes']) |
||||
except: |
||||
try: |
||||
row['discount_policy'] = eval(row['discount_policy']) |
||||
except: |
||||
pass |
||||
|
||||
class CustomManyToManyWidget(widgets.ManyToManyWidget): |
||||
def clean(self, value, row=None, *args, **kwargs): |
||||
t1 = super(CustomManyToManyWidget, self).clean(value) |
||||
return self.model.objects.get(name=t1) if t1 else None |
||||
|
||||
|
||||
# class CustomForeignKeyWidget(widgets.ForeignKeyWidget): |
||||
# def clean(self, value, row=None, *args, **kwargs): |
||||
# return self.model.objects.get_or_create(name=value)[0] |
||||
|
||||
# class ProductImageInline(admin.TabularInline): |
||||
# model = ProductImage |
||||
# extra = 0 |
||||
|
||||
# class ProductAttributeInline(admin.TabularInline): |
||||
# model = ProductAttribute |
||||
# extra = 1 |
||||
# verbose_name_plural = 'ProductAttribute' |
||||
# suit_classes = 'suit-tab suit-tab-PA' |
||||
# |
||||
class AttributeChoiceValueInline(admin.TabularInline): |
||||
model = AttributeChoiceValue |
||||
# prepopulated_fields = {'slug': ('name',)} |
||||
extra = 1 |
||||
verbose_name_plural = 'AttributeChoiceValue' |
||||
suit_classes = 'suit-tab suit-tab-ACV' |
||||
# |
||||
class OfferInline(admin.TabularInline): |
||||
model = Offer |
||||
extra = 1 |
||||
verbose_name_plural = 'Offers' |
||||
suit_classes = 'suit-tab suit-tab-offers' |
||||
|
||||
class ProductCategoryAdmin(admin.ModelAdmin): |
||||
list_display = [field.name for field in ProductCategory._meta.fields] |
||||
|
||||
class Meta: |
||||
model = ProductCategory |
||||
|
||||
# class AttributeChoiceValueAdmin(admin.ModelAdmin): |
||||
# list_display = [field.name for field in ProductCategory._meta.fields] |
||||
# |
||||
# class Meta: |
||||
# model = AttributeChoiceValue |
||||
# |
||||
# admin.site.register(AttributeChoiceValue, AttributeChoiceValueAdmin) |
||||
|
||||
class ProductAttributeAdmin(admin.ModelAdmin): |
||||
list_display = [field.name for field in ProductAttribute._meta.fields] |
||||
inlines = [AttributeChoiceValueInline] |
||||
# prepopulated_fields = {'slug': ('name',)} |
||||
|
||||
suit_form_tabs = (('general', 'General'), |
||||
('ACV', 'AttributeValues'),) |
||||
|
||||
class Meta: |
||||
model = ProductAttribute |
||||
|
||||
admin.site.register(ProductAttribute, ProductAttributeAdmin) |
||||
|
||||
class ProducerAdmin(admin.ModelAdmin): |
||||
list_display = [field.name for field in Producer._meta.fields] |
||||
|
||||
class Meta: |
||||
model = Producer |
||||
|
||||
admin.site.register(Producer, ProducerAdmin) |
||||
|
||||
class ProductResource(CustomModelResource): |
||||
# id = fields.Field(default=generate_Jid(prefix='J'), |
||||
# readonly=True, |
||||
# widget=widgets.CharWidget(), |
||||
# ) |
||||
|
||||
name = fields.Field(column_name='name', attribute='name', |
||||
default=None, |
||||
widget=widgets.CharWidget(), |
||||
) |
||||
# price = fields.Field(column_name='price', attribute='price', |
||||
# default=0, |
||||
# widget=widgets.DecimalWidget(), |
||||
# ) |
||||
description = fields.Field(column_name='description', attribute='description', |
||||
default=None, |
||||
widget=widgets.CharWidget(), |
||||
) |
||||
|
||||
# producer = fields.Field(column_name='producer', attribute='producer', |
||||
# default=None, |
||||
# widget=widgets.CharWidget(), |
||||
# ) |
||||
|
||||
category = fields.Field(column_name='category', attribute='category', |
||||
default=None, |
||||
widget=widgets.ForeignKeyWidget(ProductCategory, field='name'), |
||||
) |
||||
producer = fields.Field(column_name='producer', attribute='producer', |
||||
default=None, |
||||
widget=widgets.ForeignKeyWidget(Producer, field='name'), |
||||
) |
||||
attributes = fields.Field(column_name='attributes', attribute='attributes', |
||||
default=None, |
||||
widget=CustomManyToManyWidget(ProductAttribute, field="name"), |
||||
) |
||||
is_active = fields.Field(column_name='is_active', attribute='is_active', |
||||
default=1, |
||||
widget=widgets.BooleanWidget()) |
||||
|
||||
discount_policy = fields.Field(column_name='discount_policy', attribute='discount_policy', |
||||
default={}, |
||||
widget=widgets.CharWidget()) |
||||
|
||||
# delete = fields.Field(column_name='delete', attribute='delete', |
||||
# default=0, |
||||
# widget=widgets.BooleanWidget()) |
||||
|
||||
# def for_delete(self, row, instance): |
||||
# return self.fields['delete'].clean(row) |
||||
|
||||
class Meta: |
||||
model = Product |
||||
fields = ('id', 'name', 'description', 'producer', 'category', 'is_active', 'attributes', 'discount_policy') |
||||
export_order = ('id', 'name', 'producer', 'is_active', 'category', 'attributes', 'description', 'discount_policy') |
||||
# import_id_fields = ('name',) |
||||
|
||||
def dehydrate_str_choices(self, obj): |
||||
if obj.id: |
||||
return obj.str_choices() |
||||
|
||||
class ProductAdmin(ImportExportModelAdmin): |
||||
list_display = ['id', 'name', 'category', 'producer', 'is_active'] |
||||
inlines = [OfferInline] |
||||
list_filter = ['is_active', 'created', 'updated', 'category'] |
||||
list_editable = ['is_active'] |
||||
# prepopulated_fields = {'slug': ('name',)} |
||||
search_fields = ['name', 'id'] |
||||
|
||||
suit_form_tabs = (('general', 'General'), |
||||
('offers', 'Offers'),) |
||||
|
||||
resource_class = ProductResource |
||||
|
||||
# class Meta: |
||||
# model = Product |
||||
|
||||
class OfferResource(CustomModelResource): |
||||
name = fields.Field(column_name='name', attribute='name', |
||||
default=None, |
||||
widget=widgets.CharWidget(), |
||||
) |
||||
|
||||
price = fields.Field(column_name='price', attribute='price', |
||||
default=0, |
||||
widget=widgets.DecimalWidget(), |
||||
) |
||||
|
||||
product = fields.Field(column_name='product', attribute='product', |
||||
widget=widgets.ForeignKeyWidget(Product, field='name'), |
||||
) |
||||
|
||||
is_active = fields.Field(column_name='is_active', attribute='is_active', |
||||
default=1, |
||||
widget=widgets.BooleanWidget()) |
||||
|
||||
attributes = fields.Field(column_name='attributes', attribute='attributes', |
||||
default={}, |
||||
widget=widgets.CharWidget()) |
||||
|
||||
class Meta: |
||||
model = Offer |
||||
fields = ('name', 'product', 'price', 'is_active', 'attributes') |
||||
export_order = ('name', 'product', 'attributes', 'is_active', 'price') |
||||
import_id_fields = ('name',) |
||||
|
||||
class OfferAdmin(ImportExportModelAdmin): |
||||
list_display = ['id', 'name', 'product', 'price', 'is_active', 'attributes'] |
||||
resource_class = OfferResource |
||||
# class ProductImageAdmin(admin.ModelAdmin): |
||||
# list_display = [field.name for field in ProductImage._meta.fields] |
||||
# |
||||
# class Meta: |
||||
# model = ProductImage |
||||
|
||||
# admin.site.register(ProductImage, ProductImageAdmin) |
||||
admin.site.register(ProductCategory, ProductCategoryAdmin) |
||||
admin.site.register(Product, ProductAdmin) |
||||
admin.site.register(Offer, OfferAdmin) |
||||
@ -1,5 +0,0 @@ |
||||
from django.apps import AppConfig |
||||
|
||||
|
||||
class ProductsConfig(AppConfig): |
||||
name = 'products' |
||||
@ -1,31 +0,0 @@ |
||||
from haystack.forms import FacetedSearchForm |
||||
|
||||
|
||||
class FacetedProductSearchForm(FacetedSearchForm): |
||||
def __init__(self, *args, **kwargs): |
||||
data = dict(kwargs.get("data", [])) |
||||
self.categories = data.get('category', []) |
||||
self.producers = data.get('producer', []) |
||||
super(FacetedProductSearchForm, self).__init__(*args, **kwargs) |
||||
|
||||
def search(self): |
||||
sqs = super(FacetedProductSearchForm, self).search() |
||||
if self.categories: |
||||
query = None |
||||
for category in self.categories: |
||||
if query: |
||||
query += u' OR ' |
||||
else: |
||||
query = u'' |
||||
query += u'"%s"' % sqs.query.clean(category) |
||||
sqs = sqs.narrow(u'category_exact:%s' % query) |
||||
if self.producers: |
||||
query = None |
||||
for producer in self.producers: |
||||
if query: |
||||
query += u' OR ' |
||||
else: |
||||
query = u'' |
||||
query += u'"%s"' % sqs.query.clean(producer) |
||||
sqs = sqs.narrow(u'brand_exact:%s' % query) |
||||
return sqs |
||||
@ -1,169 +0,0 @@ |
||||
from django.db import models |
||||
from django.core.urlresolvers import reverse |
||||
from django.contrib.postgres.fields import HStoreField |
||||
from autoslug import AutoSlugField |
||||
import mptt |
||||
import decimal |
||||
from mptt.models import MPTTModel, TreeForeignKey |
||||
|
||||
|
||||
class ProductAttribute(models.Model): |
||||
name = models.CharField(max_length=64, blank=True, null=True, default=None) |
||||
slug = AutoSlugField(populate_from='name') |
||||
|
||||
def __str__(self): |
||||
return self.name |
||||
|
||||
class Meta: |
||||
ordering = ('slug',) |
||||
verbose_name = 'Product attribute' |
||||
verbose_name_plural = 'Product attributes' |
||||
|
||||
class AttributeChoiceValue(models.Model): |
||||
name = models.CharField(max_length=64, blank=True, null=True, default=None) |
||||
slug = AutoSlugField(populate_from='name') |
||||
attribute = models.ForeignKey(ProductAttribute, on_delete=models.CASCADE, related_name='values') |
||||
|
||||
def __str__(self): |
||||
return self.name |
||||
|
||||
class Meta: |
||||
unique_together = ('name', 'attribute') |
||||
verbose_name = 'attribute choices value' |
||||
verbose_name_plural = 'attribute choices values' |
||||
|
||||
class Producer(models.Model): |
||||
name = models.CharField(max_length=64, blank=True, null=True, default=None) |
||||
slug = AutoSlugField(populate_from='name') |
||||
image = models.ImageField(upload_to='producers/%Y/%m/%d/', blank=True, verbose_name="image of producer") |
||||
is_active = models.BooleanField(default=True) |
||||
|
||||
def __str__(self): |
||||
return self.name |
||||
|
||||
def get_absolute_url(self): |
||||
return reverse('products:CategoriesListByProducer', args=[self.slug]) |
||||
|
||||
class Meta: |
||||
verbose_name = 'Producer' |
||||
verbose_name_plural = 'Producers' |
||||
|
||||
class ProductCategory(MPTTModel): |
||||
name = models.CharField(db_index=True, unique=True, max_length=64, blank=True, null=True, default=None) |
||||
slug = AutoSlugField(populate_from='name') |
||||
is_active = models.BooleanField(default=True) |
||||
producer = models.ForeignKey(Producer, null=True, blank=True, related_name='categories') |
||||
parent = TreeForeignKey('self', null=True, blank=True, related_name='children') |
||||
image = models.ImageField(upload_to='categories/%Y/%m/%d/', blank=True, verbose_name="image of category") |
||||
# category_attributes = models.ManyToManyField(ProductAttribute, related_name='categories', blank=True) |
||||
|
||||
def __str__(self): |
||||
return self.name |
||||
|
||||
class Meta: |
||||
verbose_name = 'Product''s category' |
||||
verbose_name_plural = 'Category of products' |
||||
ordering = ('tree_id', 'level') |
||||
|
||||
class MPTTMeta: |
||||
order_insertion_by = ['name'] |
||||
|
||||
def get_absolute_url(self): |
||||
return reverse('products:ProductListByCategory', args=[self.producer.slug, self.slug]) |
||||
|
||||
mptt.register(ProductCategory, order_insertion_py=['name']) |
||||
|
||||
# class ProductClass(models.Model): |
||||
# name = models.CharField(max_length=64, blank=True, null=True, default=None) |
||||
# has_variants = models.BooleanField(default=True) |
||||
# # product_attributes = models.ManyToManyField(ProductAttribute, related_name='products_class', blank=True) |
||||
# variant_attributes = models.ManyToManyField(ProductAttribute, related_name='variants_class', blank=True) |
||||
# |
||||
# def __str__(self): |
||||
# return self.name |
||||
# |
||||
# class Meta: |
||||
# verbose_name = 'product class' |
||||
# verbose_name_plural = 'product classes' |
||||
|
||||
class Product(models.Model): |
||||
name = models.CharField(max_length=64, db_index=True, blank=True, null=True, default=None) |
||||
slug = AutoSlugField(populate_from='name') |
||||
price = models.DecimalField(max_digits=10, decimal_places=2, default=0.00) |
||||
# points = models.DecimalField(max_digits=8, decimal_places=2, null=True, default=0.00) |
||||
description = models.TextField(db_index=True, blank=True, null=True, default=None) |
||||
# short_description = models.TextField(blank=True, null=True, default=None) |
||||
producer = models.ForeignKey(Producer, on_delete=models.CASCADE, related_name='products') |
||||
image = models.ImageField(upload_to='products/%Y/%m/%d/', blank=True, verbose_name="image of product") |
||||
discount = models.IntegerField(blank=True, null=True, default=0) |
||||
stock = models.PositiveIntegerField(blank=True, null=True, default=0, verbose_name="In stock") |
||||
# category = TreeForeignKey(ProductCategory, blank=True, null=True, default=None, related_name='products') |
||||
category = models.ForeignKey(ProductCategory, default=None, related_name='products') |
||||
attributes = models.ManyToManyField(ProductAttribute, related_name='categories', blank=True) |
||||
discount_policy = HStoreField(blank=True, null=True, default={}) |
||||
is_active = models.BooleanField(default=True) |
||||
# is_hit = models.BooleanField(default=False) |
||||
# is_new = models.BooleanField(default=False) |
||||
created = models.DateField(auto_now_add=True, auto_now=False) |
||||
updated = models.DateField(auto_now_add=False, auto_now=True) |
||||
|
||||
def __str__(self): |
||||
return self.name |
||||
|
||||
class Meta: |
||||
ordering = ['id'] |
||||
index_together = [ |
||||
['id', 'slug'] |
||||
] |
||||
verbose_name = 'Product' |
||||
verbose_name_plural = 'Products' |
||||
|
||||
def get_absolute_url(self): |
||||
return reverse('products:Product', args=[self.slug]) |
||||
|
||||
# def save(self, *args, **kwargs): |
||||
# if self.category: |
||||
# super(Product, self).save(*args, **kwargs) |
||||
# |
||||
# for cp in ProductClass.objects.filter(category=self.product_class): |
||||
# pp = ProductProperty.objects.filter(category_property=cp, |
||||
# product=self) |
||||
# if not pp: |
||||
# pp = ProductProperty(category_property=cp, product=self, value="--") |
||||
# pp.save() |
||||
|
||||
# class ProductImage(models.Model): |
||||
# product = models.ForeignKey(Product, on_delete=models.CASCADE, blank=True, null=True, default=None) |
||||
# image = models.ImageField(upload_to='products_images') |
||||
# is_main = models.BooleanField(default=False) |
||||
# is_active = models.BooleanField(default=True) |
||||
# created = models.DateField(auto_now_add=True, auto_now=False) |
||||
# updated = models.DateField(auto_now_add=False, auto_now=True) |
||||
# |
||||
# def __str__(self): |
||||
# return "{!s}".format(self.id) |
||||
# |
||||
# class Meta: |
||||
# verbose_name = 'Photo' |
||||
# verbose_name_plural = 'Photos' |
||||
|
||||
class Offer(models.Model): |
||||
name = models.CharField(max_length=64, blank=True, null=True, default=None) |
||||
slug = AutoSlugField(populate_from='name') |
||||
price = models.DecimalField(max_digits=8, decimal_places=2, null=True, default=0.00) |
||||
# points = models.DecimalField(max_digits=8, decimal_places=2, null=True, default=0.00) |
||||
product = models.ForeignKey(Product, on_delete=models.CASCADE, blank=True, null=True, default=None, |
||||
related_name='variants') |
||||
is_active = models.BooleanField(default=True) |
||||
attributes = HStoreField(blank=True, null=True, default={}) |
||||
|
||||
def __str__(self): |
||||
return self.name |
||||
|
||||
class Meta: |
||||
verbose_name = 'Offer' |
||||
verbose_name_plural = 'Offers' |
||||
|
||||
def save(self, *args, **kwargs): |
||||
self.points = self.price * decimal.Decimal('0.1') |
||||
super(Offer, self).save(*args, **kwargs) |
||||
@ -1,20 +0,0 @@ |
||||
import datetime |
||||
from haystack import indexes |
||||
from .models import * |
||||
|
||||
class ProductIndex(indexes.SearchIndex, indexes.Indexable): |
||||
text = indexes.EdgeNgramField(document=True, use_template=True, template_name="search/product_text.txt") |
||||
name = indexes.EdgeNgramField(model_attr='name') |
||||
description = indexes.EdgeNgramField(model_attr='description') |
||||
category = indexes.CharField(model_attr='category', faceted=True) |
||||
producer = indexes.CharField(model_attr='producer', faceted=True) |
||||
|
||||
content_auto = indexes.EdgeNgramField(model_attr='name') |
||||
|
||||
suggestions = indexes.FacetCharField() |
||||
|
||||
def get_model(self): |
||||
return Product |
||||
|
||||
def index_queryset(self, using=None): |
||||
return self.get_model().objects.all() |
||||
@ -1,3 +0,0 @@ |
||||
from django.test import TestCase |
||||
|
||||
# Create your tests here. |
||||
@ -1,33 +0,0 @@ |
||||
"""Eshop URL Configuration |
||||
|
||||
The `urlpatterns` list routes URLs to views. For more information please see: |
||||
https://docs.djangoproject.com/en/1.10/topics/http/urls/ |
||||
Examples: |
||||
Function views |
||||
1. Add an import: from my_app import views |
||||
2. Add a URL to urlpatterns: url(r'^$', views.home, name='home') |
||||
Class-based views |
||||
1. Add an import: from other_app.views import Home |
||||
2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home') |
||||
Including another URLconf |
||||
1. Import the include() function: from django.conf.urls import url, include |
||||
2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) |
||||
""" |
||||
from django.conf.urls import url |
||||
from .views import productslist, product, categorieslist, producerslist |
||||
|
||||
|
||||
urlpatterns = [ |
||||
#url(r'^product/(?P<product_id>\w+)/$', views.product, name='product'), |
||||
url(r'^$', producerslist, name='ProductList'), |
||||
|
||||
# Uncomment for elasticsearch |
||||
|
||||
# url(r'^autocomplete/$', autocomplete), |
||||
# url(r'^find/$', FacetedSearchView.as_view(), name='haystack_search'), |
||||
|
||||
|
||||
url(r'^product/(?P<product_slug>[-\w]+)/$', product, name='Product'), |
||||
url(r'^(?P<producer_slug>[-\w]+)/$', categorieslist, name='CategoriesListByProducer'), |
||||
url(r'^(?P<producer_slug>[-\w]+)/(?P<category_slug>[-\w]+)/$', productslist, name='ProductListByCategory') |
||||
] |
||||
@ -1,40 +0,0 @@ |
||||
from .models import Product |
||||
|
||||
def get_variant_picker_data(product): |
||||
variants = product.variants.all() |
||||
variant_attributes = product.attributes.all() |
||||
data = {'variants': [], 'variantAttributes': [], 'discount_policy': product.discount_policy} |
||||
|
||||
for attribute in variant_attributes: |
||||
data['variantAttributes'].append({ |
||||
'name': attribute.name, |
||||
'slug': attribute.slug, |
||||
'values': [{'name': value.name, 'slug': value.slug} for value in attribute.values.all()] |
||||
}) |
||||
|
||||
for variant in variants: |
||||
price = variant.price |
||||
|
||||
variant_data = { |
||||
'id': variant.id, |
||||
'slug': variant.slug, |
||||
'name': variant.name, |
||||
'price': int(price), |
||||
'attributes': variant.attributes, |
||||
|
||||
} |
||||
|
||||
data['variants'].append(variant_data) |
||||
|
||||
return data |
||||
|
||||
def expand_categories(categories): |
||||
products = None |
||||
new_categories = categories |
||||
for e in categories: |
||||
if e.name.startswith('None'): |
||||
products = Product.objects.filter(category=e) |
||||
new_categories = categories.exclude(pk=e.pk) |
||||
return new_categories, products |
||||
|
||||
|
||||
@ -1,79 +0,0 @@ |
||||
from django.shortcuts import render, render_to_response, get_object_or_404 |
||||
from django.contrib import auth |
||||
from django.http import JsonResponse |
||||
import json |
||||
import decimal |
||||
from cart.forms import CartAddProductForm |
||||
from .utils import * |
||||
from cart.cart import Cart |
||||
from .models import * |
||||
|
||||
# Uncomment for elasticsearch |
||||
|
||||
# from .forms import FacetedProductSearchForm |
||||
# from haystack.generic_views import FacetedSearchView as BaseFacetedSearchView |
||||
# from haystack.query import SearchQuerySet |
||||
|
||||
def serialize_decimal(obj): |
||||
if isinstance(obj, decimal.Decimal): |
||||
return str(obj) |
||||
return json.JSONEncoder.default(obj) |
||||
|
||||
def producerslist(request): |
||||
username = auth.get_user(request).username |
||||
# category = None |
||||
# categories = ProductCategory.objects.filter(level__lte=0) |
||||
# products = Product.objects.filter(is_active=True) |
||||
producers = Producer.objects.filter(is_active=True) |
||||
# if category_slug: |
||||
# category = get_object_or_404(ProductCategory, slug=category_slug) |
||||
# products = products.filter(category__in=category.get_descendants(include_self=True)) |
||||
return render(request, 'products/list.html', locals()) |
||||
|
||||
def categorieslist(request, producer_slug): |
||||
username = auth.get_user(request).username |
||||
producer = Producer.objects.get(slug=producer_slug) |
||||
_categories = ProductCategory.objects.filter(is_active=True, producer=producer) |
||||
categories, products = expand_categories(_categories) |
||||
return render(request, 'products/categorieslist.html', {'username': username, 'categories':categories, |
||||
'products': products}) |
||||
|
||||
def productslist(request, producer_slug, category_slug): |
||||
username = auth.get_user(request).username |
||||
category = ProductCategory.objects.get(slug=category_slug) |
||||
products = Product.objects.filter(is_active=True, category=category) |
||||
return render(request, 'products/productslist.html', locals()) |
||||
|
||||
def product(request, product_slug): |
||||
username = auth.get_user(request).username |
||||
product = get_object_or_404(Product, slug=product_slug, is_active=True) |
||||
cart_product_form = CartAddProductForm() |
||||
variant_picker_data = get_variant_picker_data(product) |
||||
show_variant_picker = all([v.attributes for v in product.variants.all()]) |
||||
# session_key = request.session.session_key |
||||
# if not session_key: |
||||
# request.session.cycle_key() |
||||
|
||||
return render(request, 'products/product.html', {'username': username, 'product': product, 'form': cart_product_form, |
||||
'show_variant_picker': show_variant_picker, |
||||
'variant_picker_data': variant_picker_data, |
||||
}) |
||||
|
||||
# Uncomment for elasticsearch |
||||
|
||||
# def autocomplete(request): |
||||
# sqs = SearchQuerySet().autocomplete(content_auto=request.GET.get('query', ''))[:5] |
||||
# s = [] |
||||
# for result in sqs: |
||||
# print(result) |
||||
# d = {"value": result.name, "data": result.object.slug} |
||||
# s.append(d) |
||||
# output = {'suggestions': s} |
||||
# return JsonResponse(output) |
||||
# |
||||
# class FacetedSearchView(BaseFacetedSearchView): |
||||
# form_class = FacetedProductSearchForm |
||||
# facet_fields = ['category', 'producer'] |
||||
# template_name = 'search/search.html' |
||||
# paginate_by = 3 |
||||
# context_object_name = 'object_list' |
||||
@ -1,11 +0,0 @@ |
||||
List of databases |
||||
Name | Owner | Encoding | Collate | Ctype | Access privileges |
||||
-----------+----------+----------+-------------+-------------+----------------------- |
||||
eshop_db | denis | UTF8 | en_US.UTF-8 | en_US.UTF-8 | |
||||
postgres | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | |
||||
template0 | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =c/postgres + |
||||
| | | | | postgres=CTc/postgres |
||||
template1 | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =c/postgres + |
||||
| | | | | postgres=CTc/postgres |
||||
(4 rows) |
||||
|
||||
@ -1,17 +1,59 @@ |
||||
Django==1.10.6 |
||||
celery==4.0.2 |
||||
amqp==2.3.2 |
||||
anyjson==0.3.3 |
||||
appdirs==1.4.3 |
||||
Babel==2.6.0 |
||||
billiard==3.5.0.2 |
||||
cairocffi==0.8.1 |
||||
CairoSVG==2.1.3 |
||||
celery==4.0.0 |
||||
cffi==1.10.0 |
||||
cssselect==1.0.3 |
||||
cssselect2==0.2.1 |
||||
defusedxml==0.5.0 |
||||
diff-match-patch==20121119 |
||||
dj-database-url==0.4.2 |
||||
setuptools==35.0.2 |
||||
django-suit==0.2.25 |
||||
psycopg2==2.7.1 |
||||
Django==2.0.7 |
||||
django-appconf==1.0.2 |
||||
django-autoslug-iplweb==1.9.4.dev0 |
||||
django-celery==3.2.2 |
||||
django-celery-email==2.0.0 |
||||
django-debug-toolbar==1.9.1 |
||||
django-environ==0.4.5 |
||||
django-haystack==2.5.1 |
||||
django-import-export==0.5.1 |
||||
django-mptt==0.8.7 |
||||
django-haystack==2.5.1 |
||||
django-phonenumber-field==1.3.0pip |
||||
WeasyPrint==0.36 |
||||
cffi-1.10.0 |
||||
WeasyPrint==0.36 |
||||
django-mptt-urls==2.0.3 |
||||
django-phonenumber-field==1.3.0 |
||||
django-suit==0.2.25 |
||||
elasticsearch==5.0.1 |
||||
whitenoise==3.3.0 |
||||
et-xmlfile==1.0.1 |
||||
gunicorn==19.7.1 |
||||
|
||||
html5lib==1.0.1 |
||||
jdcal==1.4 |
||||
kombu==4.2.1 |
||||
lxml==4.2.3 |
||||
odfpy==1.3.6 |
||||
openpyxl==2.5.4 |
||||
packaging==17.1 |
||||
phonenumberslite==8.9.9 |
||||
Pillow==5.2.0 |
||||
psycopg2-binary==2.7.5 |
||||
pycparser==2.18 |
||||
pyparsing==2.2.0 |
||||
Pyphen==0.9.4 |
||||
pytils==0.3 |
||||
pytz==2018.5 |
||||
PyYAML==3.13 |
||||
six==1.11.0 |
||||
sqlparse==0.2.4 |
||||
tablib==0.12.1 |
||||
tinycss==0.4 |
||||
tinycss2==0.6.1 |
||||
unicodecsv==0.14.1 |
||||
urllib3==1.23 |
||||
vine==1.1.4 |
||||
WeasyPrint==0.36 |
||||
webencodings==0.5.1 |
||||
whitenoise==3.3.0 |
||||
xlrd==1.1.0 |
||||
xlwt==1.3.0 |
||||
|
||||
@ -1 +0,0 @@ |
||||
python-3.5.2 |
||||
@ -1,971 +0,0 @@ |
||||
/* |
||||
DJANGO Admin styles |
||||
*/ |
||||
|
||||
@import url("fonts.cc6140298ba7.css"); |
||||
|
||||
body { |
||||
margin: 0; |
||||
padding: 0; |
||||
font-size: 14px; |
||||
font-family: "Roboto","Lucida Grande","DejaVu Sans","Bitstream Vera Sans",Verdana,Arial,sans-serif; |
||||
color: #333; |
||||
background: #fff; |
||||
} |
||||
|
||||
/* LINKS */ |
||||
|
||||
a:link, a:visited { |
||||
color: #447e9b; |
||||
text-decoration: none; |
||||
} |
||||
|
||||
a:focus, a:hover { |
||||
color: #036; |
||||
} |
||||
|
||||
a:focus { |
||||
text-decoration: underline; |
||||
} |
||||
|
||||
a img { |
||||
border: none; |
||||
} |
||||
|
||||
a.section:link, a.section:visited { |
||||
color: #fff; |
||||
text-decoration: none; |
||||
} |
||||
|
||||
a.section:focus, a.section:hover { |
||||
text-decoration: underline; |
||||
} |
||||
|
||||
/* GLOBAL DEFAULTS */ |
||||
|
||||
p, ol, ul, dl { |
||||
margin: .2em 0 .8em 0; |
||||
} |
||||
|
||||
p { |
||||
padding: 0; |
||||
line-height: 140%; |
||||
} |
||||
|
||||
h1,h2,h3,h4,h5 { |
||||
font-weight: bold; |
||||
} |
||||
|
||||
h1 { |
||||
margin: 0 0 20px; |
||||
font-weight: 300; |
||||
font-size: 20px; |
||||
color: #666; |
||||
} |
||||
|
||||
h2 { |
||||
font-size: 16px; |
||||
margin: 1em 0 .5em 0; |
||||
} |
||||
|
||||
h2.subhead { |
||||
font-weight: normal; |
||||
margin-top: 0; |
||||
} |
||||
|
||||
h3 { |
||||
font-size: 14px; |
||||
margin: .8em 0 .3em 0; |
||||
color: #666; |
||||
font-weight: bold; |
||||
} |
||||
|
||||
h4 { |
||||
font-size: 12px; |
||||
margin: 1em 0 .8em 0; |
||||
padding-bottom: 3px; |
||||
} |
||||
|
||||
h5 { |
||||
font-size: 10px; |
||||
margin: 1.5em 0 .5em 0; |
||||
color: #666; |
||||
text-transform: uppercase; |
||||
letter-spacing: 1px; |
||||
} |
||||
|
||||
ul li { |
||||
list-style-type: square; |
||||
padding: 1px 0; |
||||
} |
||||
|
||||
li ul { |
||||
margin-bottom: 0; |
||||
} |
||||
|
||||
li, dt, dd { |
||||
font-size: 13px; |
||||
line-height: 20px; |
||||
} |
||||
|
||||
dt { |
||||
font-weight: bold; |
||||
margin-top: 4px; |
||||
} |
||||
|
||||
dd { |
||||
margin-left: 0; |
||||
} |
||||
|
||||
form { |
||||
margin: 0; |
||||
padding: 0; |
||||
} |
||||
|
||||
fieldset { |
||||
margin: 0; |
||||
padding: 0; |
||||
border: none; |
||||
border-top: 1px solid #eee; |
||||
} |
||||
|
||||
blockquote { |
||||
font-size: 11px; |
||||
color: #777; |
||||
margin-left: 2px; |
||||
padding-left: 10px; |
||||
border-left: 5px solid #ddd; |
||||
} |
||||
|
||||
code, pre { |
||||
font-family: "Bitstream Vera Sans Mono", Monaco, "Courier New", Courier, monospace; |
||||
color: #666; |
||||
font-size: 12px; |
||||
} |
||||
|
||||
pre.literal-block { |
||||
margin: 10px; |
||||
background: #eee; |
||||
padding: 6px 8px; |
||||
} |
||||
|
||||
code strong { |
||||
color: #930; |
||||
} |
||||
|
||||
hr { |
||||
clear: both; |
||||
color: #eee; |
||||
background-color: #eee; |
||||
height: 1px; |
||||
border: none; |
||||
margin: 0; |
||||
padding: 0; |
||||
font-size: 1px; |
||||
line-height: 1px; |
||||
} |
||||
|
||||
/* TEXT STYLES & MODIFIERS */ |
||||
|
||||
.small { |
||||
font-size: 11px; |
||||
} |
||||
|
||||
.tiny { |
||||
font-size: 10px; |
||||
} |
||||
|
||||
p.tiny { |
||||
margin-top: -2px; |
||||
} |
||||
|
||||
.mini { |
||||
font-size: 10px; |
||||
} |
||||
|
||||
p.mini { |
||||
margin-top: -3px; |
||||
} |
||||
|
||||
.help, p.help, form p.help { |
||||
font-size: 11px; |
||||
color: #999; |
||||
} |
||||
|
||||
.help-tooltip { |
||||
cursor: help; |
||||
} |
||||
|
||||
p img, h1 img, h2 img, h3 img, h4 img, td img { |
||||
vertical-align: middle; |
||||
} |
||||
|
||||
.quiet, a.quiet:link, a.quiet:visited { |
||||
color: #999; |
||||
font-weight: normal; |
||||
} |
||||
|
||||
.float-right { |
||||
float: right; |
||||
} |
||||
|
||||
.float-left { |
||||
float: left; |
||||
} |
||||
|
||||
.clear { |
||||
clear: both; |
||||
} |
||||
|
||||
.align-left { |
||||
text-align: left; |
||||
} |
||||
|
||||
.align-right { |
||||
text-align: right; |
||||
} |
||||
|
||||
.example { |
||||
margin: 10px 0; |
||||
padding: 5px 10px; |
||||
background: #efefef; |
||||
} |
||||
|
||||
.nowrap { |
||||
white-space: nowrap; |
||||
} |
||||
|
||||
/* TABLES */ |
||||
|
||||
table { |
||||
border-collapse: collapse; |
||||
border-color: #ccc; |
||||
} |
||||
|
||||
td, th { |
||||
font-size: 13px; |
||||
line-height: 16px; |
||||
border-bottom: 1px solid #eee; |
||||
vertical-align: top; |
||||
padding: 8px; |
||||
font-family: "Roboto", "Lucida Grande", Verdana, Arial, sans-serif; |
||||
} |
||||
|
||||
th { |
||||
font-weight: 600; |
||||
text-align: left; |
||||
} |
||||
|
||||
thead th, |
||||
tfoot td { |
||||
color: #666; |
||||
padding: 5px 10px; |
||||
font-size: 11px; |
||||
background: #fff; |
||||
border: none; |
||||
border-top: 1px solid #eee; |
||||
border-bottom: 1px solid #eee; |
||||
} |
||||
|
||||
tfoot td { |
||||
border-bottom: none; |
||||
border-top: 1px solid #eee; |
||||
} |
||||
|
||||
thead th.required { |
||||
color: #000; |
||||
} |
||||
|
||||
tr.alt { |
||||
background: #f6f6f6; |
||||
} |
||||
|
||||
.row1 { |
||||
background: #fff; |
||||
} |
||||
|
||||
.row2 { |
||||
background: #f9f9f9; |
||||
} |
||||
|
||||
/* SORTABLE TABLES */ |
||||
|
||||
thead th { |
||||
padding: 5px 10px; |
||||
line-height: normal; |
||||
text-transform: uppercase; |
||||
background: #f6f6f6; |
||||
} |
||||
|
||||
thead th a:link, thead th a:visited { |
||||
color: #666; |
||||
} |
||||
|
||||
thead th.sorted { |
||||
background: #eee; |
||||
} |
||||
|
||||
thead th.sorted .text { |
||||
padding-right: 42px; |
||||
} |
||||
|
||||
table thead th .text span { |
||||
padding: 8px 10px; |
||||
display: block; |
||||
} |
||||
|
||||
table thead th .text a { |
||||
display: block; |
||||
cursor: pointer; |
||||
padding: 8px 10px; |
||||
} |
||||
|
||||
table thead th .text a:focus, table thead th .text a:hover { |
||||
background: #eee; |
||||
} |
||||
|
||||
thead th.sorted a.sortremove { |
||||
visibility: hidden; |
||||
} |
||||
|
||||
table thead th.sorted:hover a.sortremove { |
||||
visibility: visible; |
||||
} |
||||
|
||||
table thead th.sorted .sortoptions { |
||||
display: block; |
||||
padding: 9px 5px 0 5px; |
||||
float: right; |
||||
text-align: right; |
||||
} |
||||
|
||||
table thead th.sorted .sortpriority { |
||||
font-size: .8em; |
||||
min-width: 12px; |
||||
text-align: center; |
||||
vertical-align: 3px; |
||||
margin-left: 2px; |
||||
margin-right: 2px; |
||||
} |
||||
|
||||
table thead th.sorted .sortoptions a { |
||||
position: relative; |
||||
width: 14px; |
||||
height: 14px; |
||||
display: inline-block; |
||||
background: url("../img/sorting-icons.3a097b59f104.svg") 0 0 no-repeat; |
||||
background-size: 14px auto; |
||||
} |
||||
|
||||
table thead th.sorted .sortoptions a.sortremove { |
||||
background-position: 0 0; |
||||
} |
||||
|
||||
table thead th.sorted .sortoptions a.sortremove:after { |
||||
content: '\\'; |
||||
position: absolute; |
||||
top: -6px; |
||||
left: 3px; |
||||
font-weight: 200; |
||||
font-size: 18px; |
||||
color: #999; |
||||
} |
||||
|
||||
table thead th.sorted .sortoptions a.sortremove:focus:after, |
||||
table thead th.sorted .sortoptions a.sortremove:hover:after { |
||||
color: #447e9b; |
||||
} |
||||
|
||||
table thead th.sorted .sortoptions a.sortremove:focus, |
||||
table thead th.sorted .sortoptions a.sortremove:hover { |
||||
background-position: 0 -14px; |
||||
} |
||||
|
||||
table thead th.sorted .sortoptions a.ascending { |
||||
background-position: 0 -28px; |
||||
} |
||||
|
||||
table thead th.sorted .sortoptions a.ascending:focus, |
||||
table thead th.sorted .sortoptions a.ascending:hover { |
||||
background-position: 0 -42px; |
||||
} |
||||
|
||||
table thead th.sorted .sortoptions a.descending { |
||||
top: 1px; |
||||
background-position: 0 -56px; |
||||
} |
||||
|
||||
table thead th.sorted .sortoptions a.descending:focus, |
||||
table thead th.sorted .sortoptions a.descending:hover { |
||||
background-position: 0 -70px; |
||||
} |
||||
|
||||
/* FORM DEFAULTS */ |
||||
|
||||
input, textarea, select, .form-row p, form .button { |
||||
margin: 2px 0; |
||||
padding: 2px 3px; |
||||
vertical-align: middle; |
||||
font-family: "Roboto", "Lucida Grande", Verdana, Arial, sans-serif; |
||||
font-weight: normal; |
||||
font-size: 13px; |
||||
} |
||||
|
||||
textarea { |
||||
vertical-align: top; |
||||
} |
||||
|
||||
input[type=text], input[type=password], input[type=email], input[type=url], |
||||
input[type=number], textarea, select, .vTextField { |
||||
border: 1px solid #ccc; |
||||
border-radius: 4px; |
||||
padding: 5px 6px; |
||||
margin-top: 0; |
||||
} |
||||
|
||||
input[type=text]:focus, input[type=password]:focus, input[type=email]:focus, |
||||
input[type=url]:focus, input[type=number]:focus, textarea:focus, select:focus, |
||||
.vTextField:focus { |
||||
border-color: #999; |
||||
} |
||||
|
||||
select { |
||||
height: 30px; |
||||
} |
||||
|
||||
select[multiple] { |
||||
min-height: 150px; |
||||
} |
||||
|
||||
/* FORM BUTTONS */ |
||||
|
||||
.button, input[type=submit], input[type=button], .submit-row input, a.button { |
||||
background: #79aec8; |
||||
padding: 10px 15px; |
||||
border: none; |
||||
border-radius: 4px; |
||||
color: #fff; |
||||
cursor: pointer; |
||||
} |
||||
|
||||
a.button { |
||||
padding: 4px 5px; |
||||
} |
||||
|
||||
.button:active, input[type=submit]:active, input[type=button]:active, |
||||
.button:focus, input[type=submit]:focus, input[type=button]:focus, |
||||
.button:hover, input[type=submit]:hover, input[type=button]:hover { |
||||
background: #609ab6; |
||||
} |
||||
|
||||
.button[disabled], input[type=submit][disabled], input[type=button][disabled] { |
||||
opacity: 0.4; |
||||
} |
||||
|
||||
.button.default, input[type=submit].default, .submit-row input.default { |
||||
float: right; |
||||
border: none; |
||||
font-weight: 400; |
||||
background: #417690; |
||||
} |
||||
|
||||
.button.default:active, input[type=submit].default:active, |
||||
.button.default:focus, input[type=submit].default:focus, |
||||
.button.default:hover, input[type=submit].default:hover { |
||||
background: #205067; |
||||
} |
||||
|
||||
.button[disabled].default, |
||||
input[type=submit][disabled].default, |
||||
input[type=button][disabled].default { |
||||
opacity: 0.4; |
||||
} |
||||
|
||||
|
||||
/* MODULES */ |
||||
|
||||
.module { |
||||
border: none; |
||||
margin-bottom: 30px; |
||||
background: #fff; |
||||
} |
||||
|
||||
.module p, .module ul, .module h3, .module h4, .module dl, .module pre { |
||||
padding-left: 10px; |
||||
padding-right: 10px; |
||||
} |
||||
|
||||
.module blockquote { |
||||
margin-left: 12px; |
||||
} |
||||
|
||||
.module ul, .module ol { |
||||
margin-left: 1.5em; |
||||
} |
||||
|
||||
.module h3 { |
||||
margin-top: .6em; |
||||
} |
||||
|
||||
.module h2, .module caption, .inline-group h2 { |
||||
margin: 0; |
||||
padding: 8px; |
||||
font-weight: 400; |
||||
font-size: 13px; |
||||
text-align: left; |
||||
background: #79aec8; |
||||
color: #fff; |
||||
} |
||||
|
||||
.module caption, |
||||
.inline-group h2 { |
||||
font-size: 12px; |
||||
letter-spacing: 0.5px; |
||||
text-transform: uppercase; |
||||
} |
||||
|
||||
.module table { |
||||
border-collapse: collapse; |
||||
} |
||||
|
||||
/* MESSAGES & ERRORS */ |
||||
|
||||
ul.messagelist { |
||||
padding: 0; |
||||
margin: 0; |
||||
} |
||||
|
||||
ul.messagelist li { |
||||
display: block; |
||||
font-weight: 400; |
||||
font-size: 13px; |
||||
padding: 10px 10px 10px 65px; |
||||
margin: 0 0 10px 0; |
||||
background: #dfd url("../img/icon-yes.d2f9f035226a.svg") 40px 12px no-repeat; |
||||
background-size: 16px auto; |
||||
color: #333; |
||||
} |
||||
|
||||
ul.messagelist li.warning { |
||||
background: #ffc url("../img/icon-alert.034cc7d8a67f.svg") 40px 14px no-repeat; |
||||
background-size: 14px auto; |
||||
} |
||||
|
||||
ul.messagelist li.error { |
||||
background: #ffefef url("../img/icon-no.439e821418cd.svg") 40px 12px no-repeat; |
||||
background-size: 16px auto; |
||||
} |
||||
|
||||
.errornote { |
||||
font-size: 14px; |
||||
font-weight: 700; |
||||
display: block; |
||||
padding: 10px 12px; |
||||
margin: 0 0 10px 0; |
||||
color: #ba2121; |
||||
border: 1px solid #ba2121; |
||||
border-radius: 4px; |
||||
background-color: #fff; |
||||
background-position: 5px 12px; |
||||
} |
||||
|
||||
ul.errorlist { |
||||
margin: 0 0 4px; |
||||
padding: 0; |
||||
color: #ba2121; |
||||
background: #fff; |
||||
} |
||||
|
||||
ul.errorlist li { |
||||
font-size: 13px; |
||||
display: block; |
||||
margin-bottom: 4px; |
||||
} |
||||
|
||||
ul.errorlist li:first-child { |
||||
margin-top: 0; |
||||
} |
||||
|
||||
ul.errorlist li a { |
||||
color: inherit; |
||||
text-decoration: underline; |
||||
} |
||||
|
||||
td ul.errorlist { |
||||
margin: 0; |
||||
padding: 0; |
||||
} |
||||
|
||||
td ul.errorlist li { |
||||
margin: 0; |
||||
} |
||||
|
||||
.form-row.errors { |
||||
margin: 0; |
||||
border: none; |
||||
border-bottom: 1px solid #eee; |
||||
background: none; |
||||
} |
||||
|
||||
.form-row.errors ul.errorlist li { |
||||
padding-left: 0; |
||||
} |
||||
|
||||
.errors input, .errors select, .errors textarea { |
||||
border: 1px solid #ba2121; |
||||
} |
||||
|
||||
div.system-message { |
||||
background: #ffc; |
||||
margin: 10px; |
||||
padding: 6px 8px; |
||||
font-size: .8em; |
||||
} |
||||
|
||||
div.system-message p.system-message-title { |
||||
padding: 4px 5px 4px 25px; |
||||
margin: 0; |
||||
color: #c11; |
||||
background: #ffefef url("../img/icon-no.439e821418cd.svg") 5px 5px no-repeat; |
||||
} |
||||
|
||||
.description { |
||||
font-size: 12px; |
||||
padding: 5px 0 0 12px; |
||||
} |
||||
|
||||
/* BREADCRUMBS */ |
||||
|
||||
div.breadcrumbs { |
||||
background: #79aec8; |
||||
padding: 10px 40px; |
||||
border: none; |
||||
font-size: 14px; |
||||
color: #c4dce8; |
||||
text-align: left; |
||||
} |
||||
|
||||
div.breadcrumbs a { |
||||
color: #fff; |
||||
} |
||||
|
||||
div.breadcrumbs a:focus, div.breadcrumbs a:hover { |
||||
color: #c4dce8; |
||||
} |
||||
|
||||
/* ACTION ICONS */ |
||||
|
||||
.addlink { |
||||
padding-left: 16px; |
||||
background: url("../img/icon-addlink.d519b3bab011.svg") 0 1px no-repeat; |
||||
} |
||||
|
||||
.changelink, .inlinechangelink { |
||||
padding-left: 16px; |
||||
background: url("../img/icon-changelink.18d2fd706348.svg") 0 1px no-repeat; |
||||
} |
||||
|
||||
.deletelink { |
||||
padding-left: 16px; |
||||
background: url("../img/icon-deletelink.564ef9dc3854.svg") 0 1px no-repeat; |
||||
} |
||||
|
||||
a.deletelink:link, a.deletelink:visited { |
||||
color: #CC3434; |
||||
} |
||||
|
||||
a.deletelink:focus, a.deletelink:hover { |
||||
color: #993333; |
||||
text-decoration: none; |
||||
} |
||||
|
||||
/* OBJECT TOOLS */ |
||||
|
||||
.object-tools { |
||||
font-size: 10px; |
||||
font-weight: bold; |
||||
padding-left: 0; |
||||
float: right; |
||||
position: relative; |
||||
margin-top: -48px; |
||||
} |
||||
|
||||
.form-row .object-tools { |
||||
margin-top: 5px; |
||||
margin-bottom: 5px; |
||||
float: none; |
||||
height: 2em; |
||||
padding-left: 3.5em; |
||||
} |
||||
|
||||
.object-tools li { |
||||
display: block; |
||||
float: left; |
||||
margin-left: 5px; |
||||
height: 16px; |
||||
} |
||||
|
||||
.object-tools a { |
||||
border-radius: 15px; |
||||
} |
||||
|
||||
.object-tools a:link, .object-tools a:visited { |
||||
display: block; |
||||
float: left; |
||||
padding: 3px 12px; |
||||
background: #999; |
||||
font-weight: 400; |
||||
font-size: 11px; |
||||
text-transform: uppercase; |
||||
letter-spacing: 0.5px; |
||||
color: #fff; |
||||
} |
||||
|
||||
.object-tools a:focus, .object-tools a:hover { |
||||
background-color: #417690; |
||||
} |
||||
|
||||
.object-tools a:focus{ |
||||
text-decoration: none; |
||||
} |
||||
|
||||
.object-tools a.viewsitelink, .object-tools a.golink,.object-tools a.addlink { |
||||
background-repeat: no-repeat; |
||||
background-position: 93% center; |
||||
padding-right: 26px; |
||||
} |
||||
|
||||
.object-tools a.viewsitelink, .object-tools a.golink { |
||||
background-image: url("../img/tooltag-arrowright.bbfb788a849e.svg"); |
||||
} |
||||
|
||||
.object-tools a.addlink { |
||||
background-image: url("../img/tooltag-add.e59d620a9742.svg"); |
||||
} |
||||
|
||||
/* OBJECT HISTORY */ |
||||
|
||||
table#change-history { |
||||
width: 100%; |
||||
} |
||||
|
||||
table#change-history tbody th { |
||||
width: 16em; |
||||
} |
||||
|
||||
/* PAGE STRUCTURE */ |
||||
|
||||
#container { |
||||
position: relative; |
||||
width: 100%; |
||||
min-width: 980px; |
||||
padding: 0; |
||||
} |
||||
|
||||
#content { |
||||
padding: 20px 40px; |
||||
} |
||||
|
||||
.dashboard #content { |
||||
width: 600px; |
||||
} |
||||
|
||||
#content-main { |
||||
float: left; |
||||
width: 100%; |
||||
} |
||||
|
||||
#content-related { |
||||
float: right; |
||||
width: 260px; |
||||
position: relative; |
||||
margin-right: -300px; |
||||
} |
||||
|
||||
#footer { |
||||
clear: both; |
||||
padding: 10px; |
||||
} |
||||
|
||||
/* COLUMN TYPES */ |
||||
|
||||
.colMS { |
||||
margin-right: 300px; |
||||
} |
||||
|
||||
.colSM { |
||||
margin-left: 300px; |
||||
} |
||||
|
||||
.colSM #content-related { |
||||
float: left; |
||||
margin-right: 0; |
||||
margin-left: -300px; |
||||
} |
||||
|
||||
.colSM #content-main { |
||||
float: right; |
||||
} |
||||
|
||||
.popup .colM { |
||||
width: auto; |
||||
} |
||||
|
||||
/* HEADER */ |
||||
|
||||
#header { |
||||
width: auto; |
||||
height: 40px; |
||||
padding: 10px 40px; |
||||
background: #417690; |
||||
line-height: 40px; |
||||
color: #ffc; |
||||
overflow: hidden; |
||||
} |
||||
|
||||
#header a:link, #header a:visited { |
||||
color: #fff; |
||||
} |
||||
|
||||
#header a:focus , #header a:hover { |
||||
text-decoration: underline; |
||||
} |
||||
|
||||
#branding { |
||||
float: left; |
||||
} |
||||
|
||||
#branding h1 { |
||||
padding: 0; |
||||
margin: 0 20px 0 0; |
||||
font-weight: 300; |
||||
font-size: 24px; |
||||
color: #f5dd5d; |
||||
} |
||||
|
||||
#branding h1, #branding h1 a:link, #branding h1 a:visited { |
||||
color: #f5dd5d; |
||||
} |
||||
|
||||
#branding h2 { |
||||
padding: 0 10px; |
||||
font-size: 14px; |
||||
margin: -8px 0 8px 0; |
||||
font-weight: normal; |
||||
color: #ffc; |
||||
} |
||||
|
||||
#branding a:hover { |
||||
text-decoration: none; |
||||
} |
||||
|
||||
#user-tools { |
||||
float: right; |
||||
padding: 0; |
||||
margin: 0 0 0 20px; |
||||
font-weight: 300; |
||||
font-size: 11px; |
||||
letter-spacing: 0.5px; |
||||
text-transform: uppercase; |
||||
text-align: right; |
||||
} |
||||
|
||||
#user-tools a { |
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.25); |
||||
} |
||||
|
||||
#user-tools a:focus, #user-tools a:hover { |
||||
text-decoration: none; |
||||
border-bottom-color: #79aec8; |
||||
color: #79aec8; |
||||
} |
||||
|
||||
/* SIDEBAR */ |
||||
|
||||
#content-related { |
||||
background: #f8f8f8; |
||||
} |
||||
|
||||
#content-related .module { |
||||
background: none; |
||||
} |
||||
|
||||
#content-related h3 { |
||||
font-size: 14px; |
||||
color: #666; |
||||
padding: 0 16px; |
||||
margin: 0 0 16px; |
||||
} |
||||
|
||||
#content-related h4 { |
||||
font-size: 13px; |
||||
} |
||||
|
||||
#content-related p { |
||||
padding-left: 16px; |
||||
padding-right: 16px; |
||||
} |
||||
|
||||
#content-related .actionlist { |
||||
padding: 0; |
||||
margin: 16px; |
||||
} |
||||
|
||||
#content-related .actionlist li { |
||||
line-height: 1.2; |
||||
margin-bottom: 10px; |
||||
padding-left: 18px; |
||||
} |
||||
|
||||
#content-related .module h2 { |
||||
background: none; |
||||
padding: 16px; |
||||
margin-bottom: 16px; |
||||
border-bottom: 1px solid #eaeaea; |
||||
font-size: 18px; |
||||
color: #333; |
||||
} |
||||
|
||||
.delete-confirmation form input[type="submit"] { |
||||
background: #ba2121; |
||||
border-radius: 4px; |
||||
padding: 10px 15px; |
||||
color: #fff; |
||||
} |
||||
|
||||
.delete-confirmation form input[type="submit"]:active, |
||||
.delete-confirmation form input[type="submit"]:focus, |
||||
.delete-confirmation form input[type="submit"]:hover { |
||||
background: #a41515; |
||||
} |
||||
|
||||
.delete-confirmation form .cancel-link { |
||||
display: inline-block; |
||||
vertical-align: middle; |
||||
height: 15px; |
||||
line-height: 15px; |
||||
background: #ddd; |
||||
border-radius: 4px; |
||||
padding: 10px 15px; |
||||
color: #333; |
||||
margin: 0 0 0 10px; |
||||
} |
||||
|
||||
.delete-confirmation form .cancel-link:active, |
||||
.delete-confirmation form .cancel-link:focus, |
||||
.delete-confirmation form .cancel-link:hover { |
||||
background: #ccc; |
||||
} |
||||
|
||||
/* POPUP */ |
||||
.popup #content { |
||||
padding: 20px; |
||||
} |
||||
|
||||
.popup #container { |
||||
min-width: 0; |
||||
} |
||||
|
||||
.popup #header { |
||||
padding: 10px 20px; |
||||
} |
||||
Binary file not shown.
@ -1,971 +0,0 @@ |
||||
/* |
||||
DJANGO Admin styles |
||||
*/ |
||||
|
||||
@import url(fonts.css); |
||||
|
||||
body { |
||||
margin: 0; |
||||
padding: 0; |
||||
font-size: 14px; |
||||
font-family: "Roboto","Lucida Grande","DejaVu Sans","Bitstream Vera Sans",Verdana,Arial,sans-serif; |
||||
color: #333; |
||||
background: #fff; |
||||
} |
||||
|
||||
/* LINKS */ |
||||
|
||||
a:link, a:visited { |
||||
color: #447e9b; |
||||
text-decoration: none; |
||||
} |
||||
|
||||
a:focus, a:hover { |
||||
color: #036; |
||||
} |
||||
|
||||
a:focus { |
||||
text-decoration: underline; |
||||
} |
||||
|
||||
a img { |
||||
border: none; |
||||
} |
||||
|
||||
a.section:link, a.section:visited { |
||||
color: #fff; |
||||
text-decoration: none; |
||||
} |
||||
|
||||
a.section:focus, a.section:hover { |
||||
text-decoration: underline; |
||||
} |
||||
|
||||
/* GLOBAL DEFAULTS */ |
||||
|
||||
p, ol, ul, dl { |
||||
margin: .2em 0 .8em 0; |
||||
} |
||||
|
||||
p { |
||||
padding: 0; |
||||
line-height: 140%; |
||||
} |
||||
|
||||
h1,h2,h3,h4,h5 { |
||||
font-weight: bold; |
||||
} |
||||
|
||||
h1 { |
||||
margin: 0 0 20px; |
||||
font-weight: 300; |
||||
font-size: 20px; |
||||
color: #666; |
||||
} |
||||
|
||||
h2 { |
||||
font-size: 16px; |
||||
margin: 1em 0 .5em 0; |
||||
} |
||||
|
||||
h2.subhead { |
||||
font-weight: normal; |
||||
margin-top: 0; |
||||
} |
||||
|
||||
h3 { |
||||
font-size: 14px; |
||||
margin: .8em 0 .3em 0; |
||||
color: #666; |
||||
font-weight: bold; |
||||
} |
||||
|
||||
h4 { |
||||
font-size: 12px; |
||||
margin: 1em 0 .8em 0; |
||||
padding-bottom: 3px; |
||||
} |
||||
|
||||
h5 { |
||||
font-size: 10px; |
||||
margin: 1.5em 0 .5em 0; |
||||
color: #666; |
||||
text-transform: uppercase; |
||||
letter-spacing: 1px; |
||||
} |
||||
|
||||
ul li { |
||||
list-style-type: square; |
||||
padding: 1px 0; |
||||
} |
||||
|
||||
li ul { |
||||
margin-bottom: 0; |
||||
} |
||||
|
||||
li, dt, dd { |
||||
font-size: 13px; |
||||
line-height: 20px; |
||||
} |
||||
|
||||
dt { |
||||
font-weight: bold; |
||||
margin-top: 4px; |
||||
} |
||||
|
||||
dd { |
||||
margin-left: 0; |
||||
} |
||||
|
||||
form { |
||||
margin: 0; |
||||
padding: 0; |
||||
} |
||||
|
||||
fieldset { |
||||
margin: 0; |
||||
padding: 0; |
||||
border: none; |
||||
border-top: 1px solid #eee; |
||||
} |
||||
|
||||
blockquote { |
||||
font-size: 11px; |
||||
color: #777; |
||||
margin-left: 2px; |
||||
padding-left: 10px; |
||||
border-left: 5px solid #ddd; |
||||
} |
||||
|
||||
code, pre { |
||||
font-family: "Bitstream Vera Sans Mono", Monaco, "Courier New", Courier, monospace; |
||||
color: #666; |
||||
font-size: 12px; |
||||
} |
||||
|
||||
pre.literal-block { |
||||
margin: 10px; |
||||
background: #eee; |
||||
padding: 6px 8px; |
||||
} |
||||
|
||||
code strong { |
||||
color: #930; |
||||
} |
||||
|
||||
hr { |
||||
clear: both; |
||||
color: #eee; |
||||
background-color: #eee; |
||||
height: 1px; |
||||
border: none; |
||||
margin: 0; |
||||
padding: 0; |
||||
font-size: 1px; |
||||
line-height: 1px; |
||||
} |
||||
|
||||
/* TEXT STYLES & MODIFIERS */ |
||||
|
||||
.small { |
||||
font-size: 11px; |
||||
} |
||||
|
||||
.tiny { |
||||
font-size: 10px; |
||||
} |
||||
|
||||
p.tiny { |
||||
margin-top: -2px; |
||||
} |
||||
|
||||
.mini { |
||||
font-size: 10px; |
||||
} |
||||
|
||||
p.mini { |
||||
margin-top: -3px; |
||||
} |
||||
|
||||
.help, p.help, form p.help { |
||||
font-size: 11px; |
||||
color: #999; |
||||
} |
||||
|
||||
.help-tooltip { |
||||
cursor: help; |
||||
} |
||||
|
||||
p img, h1 img, h2 img, h3 img, h4 img, td img { |
||||
vertical-align: middle; |
||||
} |
||||
|
||||
.quiet, a.quiet:link, a.quiet:visited { |
||||
color: #999; |
||||
font-weight: normal; |
||||
} |
||||
|
||||
.float-right { |
||||
float: right; |
||||
} |
||||
|
||||
.float-left { |
||||
float: left; |
||||
} |
||||
|
||||
.clear { |
||||
clear: both; |
||||
} |
||||
|
||||
.align-left { |
||||
text-align: left; |
||||
} |
||||
|
||||
.align-right { |
||||
text-align: right; |
||||
} |
||||
|
||||
.example { |
||||
margin: 10px 0; |
||||
padding: 5px 10px; |
||||
background: #efefef; |
||||
} |
||||
|
||||
.nowrap { |
||||
white-space: nowrap; |
||||
} |
||||
|
||||
/* TABLES */ |
||||
|
||||
table { |
||||
border-collapse: collapse; |
||||
border-color: #ccc; |
||||
} |
||||
|
||||
td, th { |
||||
font-size: 13px; |
||||
line-height: 16px; |
||||
border-bottom: 1px solid #eee; |
||||
vertical-align: top; |
||||
padding: 8px; |
||||
font-family: "Roboto", "Lucida Grande", Verdana, Arial, sans-serif; |
||||
} |
||||
|
||||
th { |
||||
font-weight: 600; |
||||
text-align: left; |
||||
} |
||||
|
||||
thead th, |
||||
tfoot td { |
||||
color: #666; |
||||
padding: 5px 10px; |
||||
font-size: 11px; |
||||
background: #fff; |
||||
border: none; |
||||
border-top: 1px solid #eee; |
||||
border-bottom: 1px solid #eee; |
||||
} |
||||
|
||||
tfoot td { |
||||
border-bottom: none; |
||||
border-top: 1px solid #eee; |
||||
} |
||||
|
||||
thead th.required { |
||||
color: #000; |
||||
} |
||||
|
||||
tr.alt { |
||||
background: #f6f6f6; |
||||
} |
||||
|
||||
.row1 { |
||||
background: #fff; |
||||
} |
||||
|
||||
.row2 { |
||||
background: #f9f9f9; |
||||
} |
||||
|
||||
/* SORTABLE TABLES */ |
||||
|
||||
thead th { |
||||
padding: 5px 10px; |
||||
line-height: normal; |
||||
text-transform: uppercase; |
||||
background: #f6f6f6; |
||||
} |
||||
|
||||
thead th a:link, thead th a:visited { |
||||
color: #666; |
||||
} |
||||
|
||||
thead th.sorted { |
||||
background: #eee; |
||||
} |
||||
|
||||
thead th.sorted .text { |
||||
padding-right: 42px; |
||||
} |
||||
|
||||
table thead th .text span { |
||||
padding: 8px 10px; |
||||
display: block; |
||||
} |
||||
|
||||
table thead th .text a { |
||||
display: block; |
||||
cursor: pointer; |
||||
padding: 8px 10px; |
||||
} |
||||
|
||||
table thead th .text a:focus, table thead th .text a:hover { |
||||
background: #eee; |
||||
} |
||||
|
||||
thead th.sorted a.sortremove { |
||||
visibility: hidden; |
||||
} |
||||
|
||||
table thead th.sorted:hover a.sortremove { |
||||
visibility: visible; |
||||
} |
||||
|
||||
table thead th.sorted .sortoptions { |
||||
display: block; |
||||
padding: 9px 5px 0 5px; |
||||
float: right; |
||||
text-align: right; |
||||
} |
||||
|
||||
table thead th.sorted .sortpriority { |
||||
font-size: .8em; |
||||
min-width: 12px; |
||||
text-align: center; |
||||
vertical-align: 3px; |
||||
margin-left: 2px; |
||||
margin-right: 2px; |
||||
} |
||||
|
||||
table thead th.sorted .sortoptions a { |
||||
position: relative; |
||||
width: 14px; |
||||
height: 14px; |
||||
display: inline-block; |
||||
background: url(../img/sorting-icons.svg) 0 0 no-repeat; |
||||
background-size: 14px auto; |
||||
} |
||||
|
||||
table thead th.sorted .sortoptions a.sortremove { |
||||
background-position: 0 0; |
||||
} |
||||
|
||||
table thead th.sorted .sortoptions a.sortremove:after { |
||||
content: '\\'; |
||||
position: absolute; |
||||
top: -6px; |
||||
left: 3px; |
||||
font-weight: 200; |
||||
font-size: 18px; |
||||
color: #999; |
||||
} |
||||
|
||||
table thead th.sorted .sortoptions a.sortremove:focus:after, |
||||
table thead th.sorted .sortoptions a.sortremove:hover:after { |
||||
color: #447e9b; |
||||
} |
||||
|
||||
table thead th.sorted .sortoptions a.sortremove:focus, |
||||
table thead th.sorted .sortoptions a.sortremove:hover { |
||||
background-position: 0 -14px; |
||||
} |
||||
|
||||
table thead th.sorted .sortoptions a.ascending { |
||||
background-position: 0 -28px; |
||||
} |
||||
|
||||
table thead th.sorted .sortoptions a.ascending:focus, |
||||
table thead th.sorted .sortoptions a.ascending:hover { |
||||
background-position: 0 -42px; |
||||
} |
||||
|
||||
table thead th.sorted .sortoptions a.descending { |
||||
top: 1px; |
||||
background-position: 0 -56px; |
||||
} |
||||
|
||||
table thead th.sorted .sortoptions a.descending:focus, |
||||
table thead th.sorted .sortoptions a.descending:hover { |
||||
background-position: 0 -70px; |
||||
} |
||||
|
||||
/* FORM DEFAULTS */ |
||||
|
||||
input, textarea, select, .form-row p, form .button { |
||||
margin: 2px 0; |
||||
padding: 2px 3px; |
||||
vertical-align: middle; |
||||
font-family: "Roboto", "Lucida Grande", Verdana, Arial, sans-serif; |
||||
font-weight: normal; |
||||
font-size: 13px; |
||||
} |
||||
|
||||
textarea { |
||||
vertical-align: top; |
||||
} |
||||
|
||||
input[type=text], input[type=password], input[type=email], input[type=url], |
||||
input[type=number], textarea, select, .vTextField { |
||||
border: 1px solid #ccc; |
||||
border-radius: 4px; |
||||
padding: 5px 6px; |
||||
margin-top: 0; |
||||
} |
||||
|
||||
input[type=text]:focus, input[type=password]:focus, input[type=email]:focus, |
||||
input[type=url]:focus, input[type=number]:focus, textarea:focus, select:focus, |
||||
.vTextField:focus { |
||||
border-color: #999; |
||||
} |
||||
|
||||
select { |
||||
height: 30px; |
||||
} |
||||
|
||||
select[multiple] { |
||||
min-height: 150px; |
||||
} |
||||
|
||||
/* FORM BUTTONS */ |
||||
|
||||
.button, input[type=submit], input[type=button], .submit-row input, a.button { |
||||
background: #79aec8; |
||||
padding: 10px 15px; |
||||
border: none; |
||||
border-radius: 4px; |
||||
color: #fff; |
||||
cursor: pointer; |
||||
} |
||||
|
||||
a.button { |
||||
padding: 4px 5px; |
||||
} |
||||
|
||||
.button:active, input[type=submit]:active, input[type=button]:active, |
||||
.button:focus, input[type=submit]:focus, input[type=button]:focus, |
||||
.button:hover, input[type=submit]:hover, input[type=button]:hover { |
||||
background: #609ab6; |
||||
} |
||||
|
||||
.button[disabled], input[type=submit][disabled], input[type=button][disabled] { |
||||
opacity: 0.4; |
||||
} |
||||
|
||||
.button.default, input[type=submit].default, .submit-row input.default { |
||||
float: right; |
||||
border: none; |
||||
font-weight: 400; |
||||
background: #417690; |
||||
} |
||||
|
||||
.button.default:active, input[type=submit].default:active, |
||||
.button.default:focus, input[type=submit].default:focus, |
||||
.button.default:hover, input[type=submit].default:hover { |
||||
background: #205067; |
||||
} |
||||
|
||||
.button[disabled].default, |
||||
input[type=submit][disabled].default, |
||||
input[type=button][disabled].default { |
||||
opacity: 0.4; |
||||
} |
||||
|
||||
|
||||
/* MODULES */ |
||||
|
||||
.module { |
||||
border: none; |
||||
margin-bottom: 30px; |
||||
background: #fff; |
||||
} |
||||
|
||||
.module p, .module ul, .module h3, .module h4, .module dl, .module pre { |
||||
padding-left: 10px; |
||||
padding-right: 10px; |
||||
} |
||||
|
||||
.module blockquote { |
||||
margin-left: 12px; |
||||
} |
||||
|
||||
.module ul, .module ol { |
||||
margin-left: 1.5em; |
||||
} |
||||
|
||||
.module h3 { |
||||
margin-top: .6em; |
||||
} |
||||
|
||||
.module h2, .module caption, .inline-group h2 { |
||||
margin: 0; |
||||
padding: 8px; |
||||
font-weight: 400; |
||||
font-size: 13px; |
||||
text-align: left; |
||||
background: #79aec8; |
||||
color: #fff; |
||||
} |
||||
|
||||
.module caption, |
||||
.inline-group h2 { |
||||
font-size: 12px; |
||||
letter-spacing: 0.5px; |
||||
text-transform: uppercase; |
||||
} |
||||
|
||||
.module table { |
||||
border-collapse: collapse; |
||||
} |
||||
|
||||
/* MESSAGES & ERRORS */ |
||||
|
||||
ul.messagelist { |
||||
padding: 0; |
||||
margin: 0; |
||||
} |
||||
|
||||
ul.messagelist li { |
||||
display: block; |
||||
font-weight: 400; |
||||
font-size: 13px; |
||||
padding: 10px 10px 10px 65px; |
||||
margin: 0 0 10px 0; |
||||
background: #dfd url(../img/icon-yes.svg) 40px 12px no-repeat; |
||||
background-size: 16px auto; |
||||
color: #333; |
||||
} |
||||
|
||||
ul.messagelist li.warning { |
||||
background: #ffc url(../img/icon-alert.svg) 40px 14px no-repeat; |
||||
background-size: 14px auto; |
||||
} |
||||
|
||||
ul.messagelist li.error { |
||||
background: #ffefef url(../img/icon-no.svg) 40px 12px no-repeat; |
||||
background-size: 16px auto; |
||||
} |
||||
|
||||
.errornote { |
||||
font-size: 14px; |
||||
font-weight: 700; |
||||
display: block; |
||||
padding: 10px 12px; |
||||
margin: 0 0 10px 0; |
||||
color: #ba2121; |
||||
border: 1px solid #ba2121; |
||||
border-radius: 4px; |
||||
background-color: #fff; |
||||
background-position: 5px 12px; |
||||
} |
||||
|
||||
ul.errorlist { |
||||
margin: 0 0 4px; |
||||
padding: 0; |
||||
color: #ba2121; |
||||
background: #fff; |
||||
} |
||||
|
||||
ul.errorlist li { |
||||
font-size: 13px; |
||||
display: block; |
||||
margin-bottom: 4px; |
||||
} |
||||
|
||||
ul.errorlist li:first-child { |
||||
margin-top: 0; |
||||
} |
||||
|
||||
ul.errorlist li a { |
||||
color: inherit; |
||||
text-decoration: underline; |
||||
} |
||||
|
||||
td ul.errorlist { |
||||
margin: 0; |
||||
padding: 0; |
||||
} |
||||
|
||||
td ul.errorlist li { |
||||
margin: 0; |
||||
} |
||||
|
||||
.form-row.errors { |
||||
margin: 0; |
||||
border: none; |
||||
border-bottom: 1px solid #eee; |
||||
background: none; |
||||
} |
||||
|
||||
.form-row.errors ul.errorlist li { |
||||
padding-left: 0; |
||||
} |
||||
|
||||
.errors input, .errors select, .errors textarea { |
||||
border: 1px solid #ba2121; |
||||
} |
||||
|
||||
div.system-message { |
||||
background: #ffc; |
||||
margin: 10px; |
||||
padding: 6px 8px; |
||||
font-size: .8em; |
||||
} |
||||
|
||||
div.system-message p.system-message-title { |
||||
padding: 4px 5px 4px 25px; |
||||
margin: 0; |
||||
color: #c11; |
||||
background: #ffefef url(../img/icon-no.svg) 5px 5px no-repeat; |
||||
} |
||||
|
||||
.description { |
||||
font-size: 12px; |
||||
padding: 5px 0 0 12px; |
||||
} |
||||
|
||||
/* BREADCRUMBS */ |
||||
|
||||
div.breadcrumbs { |
||||
background: #79aec8; |
||||
padding: 10px 40px; |
||||
border: none; |
||||
font-size: 14px; |
||||
color: #c4dce8; |
||||
text-align: left; |
||||
} |
||||
|
||||
div.breadcrumbs a { |
||||
color: #fff; |
||||
} |
||||
|
||||
div.breadcrumbs a:focus, div.breadcrumbs a:hover { |
||||
color: #c4dce8; |
||||
} |
||||
|
||||
/* ACTION ICONS */ |
||||
|
||||
.addlink { |
||||
padding-left: 16px; |
||||
background: url(../img/icon-addlink.svg) 0 1px no-repeat; |
||||
} |
||||
|
||||
.changelink, .inlinechangelink { |
||||
padding-left: 16px; |
||||
background: url(../img/icon-changelink.svg) 0 1px no-repeat; |
||||
} |
||||
|
||||
.deletelink { |
||||
padding-left: 16px; |
||||
background: url(../img/icon-deletelink.svg) 0 1px no-repeat; |
||||
} |
||||
|
||||
a.deletelink:link, a.deletelink:visited { |
||||
color: #CC3434; |
||||
} |
||||
|
||||
a.deletelink:focus, a.deletelink:hover { |
||||
color: #993333; |
||||
text-decoration: none; |
||||
} |
||||
|
||||
/* OBJECT TOOLS */ |
||||
|
||||
.object-tools { |
||||
font-size: 10px; |
||||
font-weight: bold; |
||||
padding-left: 0; |
||||
float: right; |
||||
position: relative; |
||||
margin-top: -48px; |
||||
} |
||||
|
||||
.form-row .object-tools { |
||||
margin-top: 5px; |
||||
margin-bottom: 5px; |
||||
float: none; |
||||
height: 2em; |
||||
padding-left: 3.5em; |
||||
} |
||||
|
||||
.object-tools li { |
||||
display: block; |
||||
float: left; |
||||
margin-left: 5px; |
||||
height: 16px; |
||||
} |
||||
|
||||
.object-tools a { |
||||
border-radius: 15px; |
||||
} |
||||
|
||||
.object-tools a:link, .object-tools a:visited { |
||||
display: block; |
||||
float: left; |
||||
padding: 3px 12px; |
||||
background: #999; |
||||
font-weight: 400; |
||||
font-size: 11px; |
||||
text-transform: uppercase; |
||||
letter-spacing: 0.5px; |
||||
color: #fff; |
||||
} |
||||
|
||||
.object-tools a:focus, .object-tools a:hover { |
||||
background-color: #417690; |
||||
} |
||||
|
||||
.object-tools a:focus{ |
||||
text-decoration: none; |
||||
} |
||||
|
||||
.object-tools a.viewsitelink, .object-tools a.golink,.object-tools a.addlink { |
||||
background-repeat: no-repeat; |
||||
background-position: 93% center; |
||||
padding-right: 26px; |
||||
} |
||||
|
||||
.object-tools a.viewsitelink, .object-tools a.golink { |
||||
background-image: url(../img/tooltag-arrowright.svg); |
||||
} |
||||
|
||||
.object-tools a.addlink { |
||||
background-image: url(../img/tooltag-add.svg); |
||||
} |
||||
|
||||
/* OBJECT HISTORY */ |
||||
|
||||
table#change-history { |
||||
width: 100%; |
||||
} |
||||
|
||||
table#change-history tbody th { |
||||
width: 16em; |
||||
} |
||||
|
||||
/* PAGE STRUCTURE */ |
||||
|
||||
#container { |
||||
position: relative; |
||||
width: 100%; |
||||
min-width: 980px; |
||||
padding: 0; |
||||
} |
||||
|
||||
#content { |
||||
padding: 20px 40px; |
||||
} |
||||
|
||||
.dashboard #content { |
||||
width: 600px; |
||||
} |
||||
|
||||
#content-main { |
||||
float: left; |
||||
width: 100%; |
||||
} |
||||
|
||||
#content-related { |
||||
float: right; |
||||
width: 260px; |
||||
position: relative; |
||||
margin-right: -300px; |
||||
} |
||||
|
||||
#footer { |
||||
clear: both; |
||||
padding: 10px; |
||||
} |
||||
|
||||
/* COLUMN TYPES */ |
||||
|
||||
.colMS { |
||||
margin-right: 300px; |
||||
} |
||||
|
||||
.colSM { |
||||
margin-left: 300px; |
||||
} |
||||
|
||||
.colSM #content-related { |
||||
float: left; |
||||
margin-right: 0; |
||||
margin-left: -300px; |
||||
} |
||||
|
||||
.colSM #content-main { |
||||
float: right; |
||||
} |
||||
|
||||
.popup .colM { |
||||
width: auto; |
||||
} |
||||
|
||||
/* HEADER */ |
||||
|
||||
#header { |
||||
width: auto; |
||||
height: 40px; |
||||
padding: 10px 40px; |
||||
background: #417690; |
||||
line-height: 40px; |
||||
color: #ffc; |
||||
overflow: hidden; |
||||
} |
||||
|
||||
#header a:link, #header a:visited { |
||||
color: #fff; |
||||
} |
||||
|
||||
#header a:focus , #header a:hover { |
||||
text-decoration: underline; |
||||
} |
||||
|
||||
#branding { |
||||
float: left; |
||||
} |
||||
|
||||
#branding h1 { |
||||
padding: 0; |
||||
margin: 0 20px 0 0; |
||||
font-weight: 300; |
||||
font-size: 24px; |
||||
color: #f5dd5d; |
||||
} |
||||
|
||||
#branding h1, #branding h1 a:link, #branding h1 a:visited { |
||||
color: #f5dd5d; |
||||
} |
||||
|
||||
#branding h2 { |
||||
padding: 0 10px; |
||||
font-size: 14px; |
||||
margin: -8px 0 8px 0; |
||||
font-weight: normal; |
||||
color: #ffc; |
||||
} |
||||
|
||||
#branding a:hover { |
||||
text-decoration: none; |
||||
} |
||||
|
||||
#user-tools { |
||||
float: right; |
||||
padding: 0; |
||||
margin: 0 0 0 20px; |
||||
font-weight: 300; |
||||
font-size: 11px; |
||||
letter-spacing: 0.5px; |
||||
text-transform: uppercase; |
||||
text-align: right; |
||||
} |
||||
|
||||
#user-tools a { |
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.25); |
||||
} |
||||
|
||||
#user-tools a:focus, #user-tools a:hover { |
||||
text-decoration: none; |
||||
border-bottom-color: #79aec8; |
||||
color: #79aec8; |
||||
} |
||||
|
||||
/* SIDEBAR */ |
||||
|
||||
#content-related { |
||||
background: #f8f8f8; |
||||
} |
||||
|
||||
#content-related .module { |
||||
background: none; |
||||
} |
||||
|
||||
#content-related h3 { |
||||
font-size: 14px; |
||||
color: #666; |
||||
padding: 0 16px; |
||||
margin: 0 0 16px; |
||||
} |
||||
|
||||
#content-related h4 { |
||||
font-size: 13px; |
||||
} |
||||
|
||||
#content-related p { |
||||
padding-left: 16px; |
||||
padding-right: 16px; |
||||
} |
||||
|
||||
#content-related .actionlist { |
||||
padding: 0; |
||||
margin: 16px; |
||||
} |
||||
|
||||
#content-related .actionlist li { |
||||
line-height: 1.2; |
||||
margin-bottom: 10px; |
||||
padding-left: 18px; |
||||
} |
||||
|
||||
#content-related .module h2 { |
||||
background: none; |
||||
padding: 16px; |
||||
margin-bottom: 16px; |
||||
border-bottom: 1px solid #eaeaea; |
||||
font-size: 18px; |
||||
color: #333; |
||||
} |
||||
|
||||
.delete-confirmation form input[type="submit"] { |
||||
background: #ba2121; |
||||
border-radius: 4px; |
||||
padding: 10px 15px; |
||||
color: #fff; |
||||
} |
||||
|
||||
.delete-confirmation form input[type="submit"]:active, |
||||
.delete-confirmation form input[type="submit"]:focus, |
||||
.delete-confirmation form input[type="submit"]:hover { |
||||
background: #a41515; |
||||
} |
||||
|
||||
.delete-confirmation form .cancel-link { |
||||
display: inline-block; |
||||
vertical-align: middle; |
||||
height: 15px; |
||||
line-height: 15px; |
||||
background: #ddd; |
||||
border-radius: 4px; |
||||
padding: 10px 15px; |
||||
color: #333; |
||||
margin: 0 0 0 10px; |
||||
} |
||||
|
||||
.delete-confirmation form .cancel-link:active, |
||||
.delete-confirmation form .cancel-link:focus, |
||||
.delete-confirmation form .cancel-link:hover { |
||||
background: #ccc; |
||||
} |
||||
|
||||
/* POPUP */ |
||||
.popup #content { |
||||
padding: 20px; |
||||
} |
||||
|
||||
.popup #container { |
||||
min-width: 0; |
||||
} |
||||
|
||||
.popup #header { |
||||
padding: 10px 20px; |
||||
} |
||||
Binary file not shown.
@ -1,342 +0,0 @@ |
||||
/* CHANGELISTS */ |
||||
|
||||
#changelist { |
||||
position: relative; |
||||
width: 100%; |
||||
} |
||||
|
||||
#changelist table { |
||||
width: 100%; |
||||
} |
||||
|
||||
.change-list .hiddenfields { display:none; } |
||||
|
||||
.change-list .filtered table { |
||||
border-right: none; |
||||
} |
||||
|
||||
.change-list .filtered { |
||||
min-height: 400px; |
||||
} |
||||
|
||||
.change-list .filtered .results, .change-list .filtered .paginator, |
||||
.filtered #toolbar, .filtered div.xfull { |
||||
margin-right: 280px; |
||||
width: auto; |
||||
} |
||||
|
||||
.change-list .filtered table tbody th { |
||||
padding-right: 1em; |
||||
} |
||||
|
||||
#changelist-form .results { |
||||
overflow-x: auto; |
||||
} |
||||
|
||||
#changelist .toplinks { |
||||
border-bottom: 1px solid #ddd; |
||||
} |
||||
|
||||
#changelist .paginator { |
||||
color: #666; |
||||
border-bottom: 1px solid #eee; |
||||
background: #fff; |
||||
overflow: hidden; |
||||
} |
||||
|
||||
/* CHANGELIST TABLES */ |
||||
|
||||
#changelist table thead th { |
||||
padding: 0; |
||||
white-space: nowrap; |
||||
vertical-align: middle; |
||||
} |
||||
|
||||
#changelist table thead th.action-checkbox-column { |
||||
width: 1.5em; |
||||
text-align: center; |
||||
} |
||||
|
||||
#changelist table tbody td.action-checkbox { |
||||
text-align: center; |
||||
} |
||||
|
||||
#changelist table tfoot { |
||||
color: #666; |
||||
} |
||||
|
||||
/* TOOLBAR */ |
||||
|
||||
#changelist #toolbar { |
||||
padding: 8px 10px; |
||||
margin-bottom: 15px; |
||||
border-top: 1px solid #eee; |
||||
border-bottom: 1px solid #eee; |
||||
background: #f8f8f8; |
||||
color: #666; |
||||
} |
||||
|
||||
#changelist #toolbar form input { |
||||
border-radius: 4px; |
||||
font-size: 14px; |
||||
padding: 5px; |
||||
color: #333; |
||||
} |
||||
|
||||
#changelist #toolbar form #searchbar { |
||||
height: 19px; |
||||
border: 1px solid #ccc; |
||||
padding: 2px 5px; |
||||
margin: 0; |
||||
vertical-align: top; |
||||
font-size: 13px; |
||||
} |
||||
|
||||
#changelist #toolbar form #searchbar:focus { |
||||
border-color: #999; |
||||
} |
||||
|
||||
#changelist #toolbar form input[type="submit"] { |
||||
border: 1px solid #ccc; |
||||
padding: 2px 10px; |
||||
margin: 0; |
||||
vertical-align: middle; |
||||
background: #fff; |
||||
box-shadow: 0 -15px 20px -10px rgba(0, 0, 0, 0.15) inset; |
||||
cursor: pointer; |
||||
color: #333; |
||||
} |
||||
|
||||
#changelist #toolbar form input[type="submit"]:focus, |
||||
#changelist #toolbar form input[type="submit"]:hover { |
||||
border-color: #999; |
||||
} |
||||
|
||||
#changelist #changelist-search img { |
||||
vertical-align: middle; |
||||
margin-right: 4px; |
||||
} |
||||
|
||||
/* FILTER COLUMN */ |
||||
|
||||
#changelist-filter { |
||||
position: absolute; |
||||
top: 0; |
||||
right: 0; |
||||
z-index: 1000; |
||||
width: 240px; |
||||
background: #f8f8f8; |
||||
border-left: none; |
||||
margin: 0; |
||||
} |
||||
|
||||
#changelist-filter h2 { |
||||
font-size: 14px; |
||||
text-transform: uppercase; |
||||
letter-spacing: 0.5px; |
||||
padding: 5px 15px; |
||||
margin-bottom: 12px; |
||||
border-bottom: none; |
||||
} |
||||
|
||||
#changelist-filter h3 { |
||||
font-weight: 400; |
||||
font-size: 14px; |
||||
padding: 0 15px; |
||||
margin-bottom: 10px; |
||||
} |
||||
|
||||
#changelist-filter ul { |
||||
margin: 5px 0; |
||||
padding: 0 15px 15px; |
||||
border-bottom: 1px solid #eaeaea; |
||||
} |
||||
|
||||
#changelist-filter ul:last-child { |
||||
border-bottom: none; |
||||
padding-bottom: none; |
||||
} |
||||
|
||||
#changelist-filter li { |
||||
list-style-type: none; |
||||
margin-left: 0; |
||||
padding-left: 0; |
||||
} |
||||
|
||||
#changelist-filter a { |
||||
display: block; |
||||
color: #999; |
||||
} |
||||
|
||||
#changelist-filter li.selected { |
||||
border-left: 5px solid #eaeaea; |
||||
padding-left: 10px; |
||||
margin-left: -15px; |
||||
} |
||||
|
||||
#changelist-filter li.selected a { |
||||
color: #5b80b2; |
||||
} |
||||
|
||||
#changelist-filter a:focus, #changelist-filter a:hover, |
||||
#changelist-filter li.selected a:focus, |
||||
#changelist-filter li.selected a:hover { |
||||
color: #036; |
||||
} |
||||
|
||||
/* DATE DRILLDOWN */ |
||||
|
||||
.change-list ul.toplinks { |
||||
display: block; |
||||
float: left; |
||||
padding: 0; |
||||
margin: 0; |
||||
width: 100%; |
||||
} |
||||
|
||||
.change-list ul.toplinks li { |
||||
padding: 3px 6px; |
||||
font-weight: bold; |
||||
list-style-type: none; |
||||
display: inline-block; |
||||
} |
||||
|
||||
.change-list ul.toplinks .date-back a { |
||||
color: #999; |
||||
} |
||||
|
||||
.change-list ul.toplinks .date-back a:focus, |
||||
.change-list ul.toplinks .date-back a:hover { |
||||
color: #036; |
||||
} |
||||
|
||||
/* PAGINATOR */ |
||||
|
||||
.paginator { |
||||
font-size: 13px; |
||||
padding-top: 10px; |
||||
padding-bottom: 10px; |
||||
line-height: 22px; |
||||
margin: 0; |
||||
border-top: 1px solid #ddd; |
||||
} |
||||
|
||||
.paginator a:link, .paginator a:visited { |
||||
padding: 2px 6px; |
||||
background: #79aec8; |
||||
text-decoration: none; |
||||
color: #fff; |
||||
} |
||||
|
||||
.paginator a.showall { |
||||
padding: 0; |
||||
border: none; |
||||
background: none; |
||||
color: #5b80b2; |
||||
} |
||||
|
||||
.paginator a.showall:focus, .paginator a.showall:hover { |
||||
background: none; |
||||
color: #036; |
||||
} |
||||
|
||||
.paginator .end { |
||||
margin-right: 6px; |
||||
} |
||||
|
||||
.paginator .this-page { |
||||
padding: 2px 6px; |
||||
font-weight: bold; |
||||
font-size: 13px; |
||||
vertical-align: top; |
||||
} |
||||
|
||||
.paginator a:focus, .paginator a:hover { |
||||
color: white; |
||||
background: #036; |
||||
} |
||||
|
||||
/* ACTIONS */ |
||||
|
||||
.filtered .actions { |
||||
margin-right: 280px; |
||||
border-right: none; |
||||
} |
||||
|
||||
#changelist table input { |
||||
margin: 0; |
||||
vertical-align: baseline; |
||||
} |
||||
|
||||
#changelist table tbody tr.selected { |
||||
background-color: #FFFFCC; |
||||
} |
||||
|
||||
#changelist .actions { |
||||
padding: 10px; |
||||
background: #fff; |
||||
border-top: none; |
||||
border-bottom: none; |
||||
line-height: 24px; |
||||
color: #999; |
||||
} |
||||
|
||||
#changelist .actions.selected { |
||||
background: #fffccf; |
||||
border-top: 1px solid #fffee8; |
||||
border-bottom: 1px solid #edecd6; |
||||
} |
||||
|
||||
#changelist .actions span.all, |
||||
#changelist .actions span.action-counter, |
||||
#changelist .actions span.clear, |
||||
#changelist .actions span.question { |
||||
font-size: 13px; |
||||
margin: 0 0.5em; |
||||
display: none; |
||||
} |
||||
|
||||
#changelist .actions:last-child { |
||||
border-bottom: none; |
||||
} |
||||
|
||||
#changelist .actions select { |
||||
vertical-align: top; |
||||
height: 24px; |
||||
background: none; |
||||
color: #000; |
||||
border: 1px solid #ccc; |
||||
border-radius: 4px; |
||||
font-size: 14px; |
||||
padding: 0 0 0 4px; |
||||
margin: 0; |
||||
margin-left: 10px; |
||||
} |
||||
|
||||
#changelist .actions select:focus { |
||||
border-color: #999; |
||||
} |
||||
|
||||
#changelist .actions label { |
||||
display: inline-block; |
||||
vertical-align: middle; |
||||
font-size: 13px; |
||||
} |
||||
|
||||
#changelist .actions .button { |
||||
font-size: 13px; |
||||
border: 1px solid #ccc; |
||||
border-radius: 4px; |
||||
background: #fff; |
||||
box-shadow: 0 -15px 20px -10px rgba(0, 0, 0, 0.15) inset; |
||||
cursor: pointer; |
||||
height: 24px; |
||||
line-height: 1; |
||||
padding: 4px 8px; |
||||
margin: 0; |
||||
color: #333; |
||||
} |
||||
|
||||
#changelist .actions .button:focus, #changelist .actions .button:hover { |
||||
border-color: #999; |
||||
} |
||||
Binary file not shown.
@ -1,342 +0,0 @@ |
||||
/* CHANGELISTS */ |
||||
|
||||
#changelist { |
||||
position: relative; |
||||
width: 100%; |
||||
} |
||||
|
||||
#changelist table { |
||||
width: 100%; |
||||
} |
||||
|
||||
.change-list .hiddenfields { display:none; } |
||||
|
||||
.change-list .filtered table { |
||||
border-right: none; |
||||
} |
||||
|
||||
.change-list .filtered { |
||||
min-height: 400px; |
||||
} |
||||
|
||||
.change-list .filtered .results, .change-list .filtered .paginator, |
||||
.filtered #toolbar, .filtered div.xfull { |
||||
margin-right: 280px; |
||||
width: auto; |
||||
} |
||||
|
||||
.change-list .filtered table tbody th { |
||||
padding-right: 1em; |
||||
} |
||||
|
||||
#changelist-form .results { |
||||
overflow-x: auto; |
||||
} |
||||
|
||||
#changelist .toplinks { |
||||
border-bottom: 1px solid #ddd; |
||||
} |
||||
|
||||
#changelist .paginator { |
||||
color: #666; |
||||
border-bottom: 1px solid #eee; |
||||
background: #fff; |
||||
overflow: hidden; |
||||
} |
||||
|
||||
/* CHANGELIST TABLES */ |
||||
|
||||
#changelist table thead th { |
||||
padding: 0; |
||||
white-space: nowrap; |
||||
vertical-align: middle; |
||||
} |
||||
|
||||
#changelist table thead th.action-checkbox-column { |
||||
width: 1.5em; |
||||
text-align: center; |
||||
} |
||||
|
||||
#changelist table tbody td.action-checkbox { |
||||
text-align: center; |
||||
} |
||||
|
||||
#changelist table tfoot { |
||||
color: #666; |
||||
} |
||||
|
||||
/* TOOLBAR */ |
||||
|
||||
#changelist #toolbar { |
||||
padding: 8px 10px; |
||||
margin-bottom: 15px; |
||||
border-top: 1px solid #eee; |
||||
border-bottom: 1px solid #eee; |
||||
background: #f8f8f8; |
||||
color: #666; |
||||
} |
||||
|
||||
#changelist #toolbar form input { |
||||
border-radius: 4px; |
||||
font-size: 14px; |
||||
padding: 5px; |
||||
color: #333; |
||||
} |
||||
|
||||
#changelist #toolbar form #searchbar { |
||||
height: 19px; |
||||
border: 1px solid #ccc; |
||||
padding: 2px 5px; |
||||
margin: 0; |
||||
vertical-align: top; |
||||
font-size: 13px; |
||||
} |
||||
|
||||
#changelist #toolbar form #searchbar:focus { |
||||
border-color: #999; |
||||
} |
||||
|
||||
#changelist #toolbar form input[type="submit"] { |
||||
border: 1px solid #ccc; |
||||
padding: 2px 10px; |
||||
margin: 0; |
||||
vertical-align: middle; |
||||
background: #fff; |
||||
box-shadow: 0 -15px 20px -10px rgba(0, 0, 0, 0.15) inset; |
||||
cursor: pointer; |
||||
color: #333; |
||||
} |
||||
|
||||
#changelist #toolbar form input[type="submit"]:focus, |
||||
#changelist #toolbar form input[type="submit"]:hover { |
||||
border-color: #999; |
||||
} |
||||
|
||||
#changelist #changelist-search img { |
||||
vertical-align: middle; |
||||
margin-right: 4px; |
||||
} |
||||
|
||||
/* FILTER COLUMN */ |
||||
|
||||
#changelist-filter { |
||||
position: absolute; |
||||
top: 0; |
||||
right: 0; |
||||
z-index: 1000; |
||||
width: 240px; |
||||
background: #f8f8f8; |
||||
border-left: none; |
||||
margin: 0; |
||||
} |
||||
|
||||
#changelist-filter h2 { |
||||
font-size: 14px; |
||||
text-transform: uppercase; |
||||
letter-spacing: 0.5px; |
||||
padding: 5px 15px; |
||||
margin-bottom: 12px; |
||||
border-bottom: none; |
||||
} |
||||
|
||||
#changelist-filter h3 { |
||||
font-weight: 400; |
||||
font-size: 14px; |
||||
padding: 0 15px; |
||||
margin-bottom: 10px; |
||||
} |
||||
|
||||
#changelist-filter ul { |
||||
margin: 5px 0; |
||||
padding: 0 15px 15px; |
||||
border-bottom: 1px solid #eaeaea; |
||||
} |
||||
|
||||
#changelist-filter ul:last-child { |
||||
border-bottom: none; |
||||
padding-bottom: none; |
||||
} |
||||
|
||||
#changelist-filter li { |
||||
list-style-type: none; |
||||
margin-left: 0; |
||||
padding-left: 0; |
||||
} |
||||
|
||||
#changelist-filter a { |
||||
display: block; |
||||
color: #999; |
||||
} |
||||
|
||||
#changelist-filter li.selected { |
||||
border-left: 5px solid #eaeaea; |
||||
padding-left: 10px; |
||||
margin-left: -15px; |
||||
} |
||||
|
||||
#changelist-filter li.selected a { |
||||
color: #5b80b2; |
||||
} |
||||
|
||||
#changelist-filter a:focus, #changelist-filter a:hover, |
||||
#changelist-filter li.selected a:focus, |
||||
#changelist-filter li.selected a:hover { |
||||
color: #036; |
||||
} |
||||
|
||||
/* DATE DRILLDOWN */ |
||||
|
||||
.change-list ul.toplinks { |
||||
display: block; |
||||
float: left; |
||||
padding: 0; |
||||
margin: 0; |
||||
width: 100%; |
||||
} |
||||
|
||||
.change-list ul.toplinks li { |
||||
padding: 3px 6px; |
||||
font-weight: bold; |
||||
list-style-type: none; |
||||
display: inline-block; |
||||
} |
||||
|
||||
.change-list ul.toplinks .date-back a { |
||||
color: #999; |
||||
} |
||||
|
||||
.change-list ul.toplinks .date-back a:focus, |
||||
.change-list ul.toplinks .date-back a:hover { |
||||
color: #036; |
||||
} |
||||
|
||||
/* PAGINATOR */ |
||||
|
||||
.paginator { |
||||
font-size: 13px; |
||||
padding-top: 10px; |
||||
padding-bottom: 10px; |
||||
line-height: 22px; |
||||
margin: 0; |
||||
border-top: 1px solid #ddd; |
||||
} |
||||
|
||||
.paginator a:link, .paginator a:visited { |
||||
padding: 2px 6px; |
||||
background: #79aec8; |
||||
text-decoration: none; |
||||
color: #fff; |
||||
} |
||||
|
||||
.paginator a.showall { |
||||
padding: 0; |
||||
border: none; |
||||
background: none; |
||||
color: #5b80b2; |
||||
} |
||||
|
||||
.paginator a.showall:focus, .paginator a.showall:hover { |
||||
background: none; |
||||
color: #036; |
||||
} |
||||
|
||||
.paginator .end { |
||||
margin-right: 6px; |
||||
} |
||||
|
||||
.paginator .this-page { |
||||
padding: 2px 6px; |
||||
font-weight: bold; |
||||
font-size: 13px; |
||||
vertical-align: top; |
||||
} |
||||
|
||||
.paginator a:focus, .paginator a:hover { |
||||
color: white; |
||||
background: #036; |
||||
} |
||||
|
||||
/* ACTIONS */ |
||||
|
||||
.filtered .actions { |
||||
margin-right: 280px; |
||||
border-right: none; |
||||
} |
||||
|
||||
#changelist table input { |
||||
margin: 0; |
||||
vertical-align: baseline; |
||||
} |
||||
|
||||
#changelist table tbody tr.selected { |
||||
background-color: #FFFFCC; |
||||
} |
||||
|
||||
#changelist .actions { |
||||
padding: 10px; |
||||
background: #fff; |
||||
border-top: none; |
||||
border-bottom: none; |
||||
line-height: 24px; |
||||
color: #999; |
||||
} |
||||
|
||||
#changelist .actions.selected { |
||||
background: #fffccf; |
||||
border-top: 1px solid #fffee8; |
||||
border-bottom: 1px solid #edecd6; |
||||
} |
||||
|
||||
#changelist .actions span.all, |
||||
#changelist .actions span.action-counter, |
||||
#changelist .actions span.clear, |
||||
#changelist .actions span.question { |
||||
font-size: 13px; |
||||
margin: 0 0.5em; |
||||
display: none; |
||||
} |
||||
|
||||
#changelist .actions:last-child { |
||||
border-bottom: none; |
||||
} |
||||
|
||||
#changelist .actions select { |
||||
vertical-align: top; |
||||
height: 24px; |
||||
background: none; |
||||
color: #000; |
||||
border: 1px solid #ccc; |
||||
border-radius: 4px; |
||||
font-size: 14px; |
||||
padding: 0 0 0 4px; |
||||
margin: 0; |
||||
margin-left: 10px; |
||||
} |
||||
|
||||
#changelist .actions select:focus { |
||||
border-color: #999; |
||||
} |
||||
|
||||
#changelist .actions label { |
||||
display: inline-block; |
||||
vertical-align: middle; |
||||
font-size: 13px; |
||||
} |
||||
|
||||
#changelist .actions .button { |
||||
font-size: 13px; |
||||
border: 1px solid #ccc; |
||||
border-radius: 4px; |
||||
background: #fff; |
||||
box-shadow: 0 -15px 20px -10px rgba(0, 0, 0, 0.15) inset; |
||||
cursor: pointer; |
||||
height: 24px; |
||||
line-height: 1; |
||||
padding: 4px 8px; |
||||
margin: 0; |
||||
color: #333; |
||||
} |
||||
|
||||
#changelist .actions .button:focus, #changelist .actions .button:hover { |
||||
border-color: #999; |
||||
} |
||||
Binary file not shown.
@ -1,30 +0,0 @@ |
||||
/* DASHBOARD */ |
||||
|
||||
.dashboard .module table th { |
||||
width: 100%; |
||||
} |
||||
|
||||
.dashboard .module table td { |
||||
white-space: nowrap; |
||||
} |
||||
|
||||
.dashboard .module table td a { |
||||
display: block; |
||||
padding-right: .6em; |
||||
} |
||||
|
||||
/* RECENT ACTIONS MODULE */ |
||||
|
||||
.module ul.actionlist { |
||||
margin-left: 0; |
||||
} |
||||
|
||||
ul.actionlist li { |
||||
list-style-type: none; |
||||
} |
||||
|
||||
ul.actionlist li { |
||||
overflow: hidden; |
||||
text-overflow: ellipsis; |
||||
-o-text-overflow: ellipsis; |
||||
} |
||||
Binary file not shown.
@ -1,30 +0,0 @@ |
||||
/* DASHBOARD */ |
||||
|
||||
.dashboard .module table th { |
||||
width: 100%; |
||||
} |
||||
|
||||
.dashboard .module table td { |
||||
white-space: nowrap; |
||||
} |
||||
|
||||
.dashboard .module table td a { |
||||
display: block; |
||||
padding-right: .6em; |
||||
} |
||||
|
||||
/* RECENT ACTIONS MODULE */ |
||||
|
||||
.module ul.actionlist { |
||||
margin-left: 0; |
||||
} |
||||
|
||||
ul.actionlist li { |
||||
list-style-type: none; |
||||
} |
||||
|
||||
ul.actionlist li { |
||||
overflow: hidden; |
||||
text-overflow: ellipsis; |
||||
-o-text-overflow: ellipsis; |
||||
} |
||||
Binary file not shown.
@ -1,20 +0,0 @@ |
||||
@font-face { |
||||
font-family: 'Roboto'; |
||||
src: url("../fonts/Roboto-Bold-webfont.2ad99072841e.woff"); |
||||
font-weight: 700; |
||||
font-style: normal; |
||||
} |
||||
|
||||
@font-face { |
||||
font-family: 'Roboto'; |
||||
src: url("../fonts/Roboto-Regular-webfont.ec39515ae8c6.woff"); |
||||
font-weight: 400; |
||||
font-style: normal; |
||||
} |
||||
|
||||
@font-face { |
||||
font-family: 'Roboto'; |
||||
src: url("../fonts/Roboto-Light-webfont.b446c2399bb6.woff"); |
||||
font-weight: 300; |
||||
font-style: normal; |
||||
} |
||||
Binary file not shown.
@ -1,20 +0,0 @@ |
||||
@font-face { |
||||
font-family: 'Roboto'; |
||||
src: url('../fonts/Roboto-Bold-webfont.woff'); |
||||
font-weight: 700; |
||||
font-style: normal; |
||||
} |
||||
|
||||
@font-face { |
||||
font-family: 'Roboto'; |
||||
src: url('../fonts/Roboto-Regular-webfont.woff'); |
||||
font-weight: 400; |
||||
font-style: normal; |
||||
} |
||||
|
||||
@font-face { |
||||
font-family: 'Roboto'; |
||||
src: url('../fonts/Roboto-Light-webfont.woff'); |
||||
font-weight: 300; |
||||
font-style: normal; |
||||
} |
||||
Binary file not shown.
@ -1 +0,0 @@ |
||||
/* Empty CSS from Django Suit app to override original file */ |
||||
@ -1 +0,0 @@ |
||||
/* Empty CSS from Django Suit app to override original file */ |
||||
@ -1,78 +0,0 @@ |
||||
/* LOGIN FORM */ |
||||
|
||||
body.login { |
||||
background: #f8f8f8; |
||||
} |
||||
|
||||
.login #header { |
||||
height: auto; |
||||
padding: 5px 16px; |
||||
} |
||||
|
||||
.login #header h1 { |
||||
font-size: 18px; |
||||
} |
||||
|
||||
.login #header h1 a { |
||||
color: #fff; |
||||
} |
||||
|
||||
.login #content { |
||||
padding: 20px 20px 0; |
||||
} |
||||
|
||||
.login #container { |
||||
background: #fff; |
||||
border: 1px solid #eaeaea; |
||||
border-radius: 4px; |
||||
overflow: hidden; |
||||
width: 28em; |
||||
min-width: 300px; |
||||
margin: 100px auto; |
||||
} |
||||
|
||||
.login #content-main { |
||||
width: 100%; |
||||
} |
||||
|
||||
.login .form-row { |
||||
padding: 4px 0; |
||||
float: left; |
||||
width: 100%; |
||||
border-bottom: none; |
||||
} |
||||
|
||||
.login .form-row label { |
||||
padding-right: 0.5em; |
||||
line-height: 2em; |
||||
font-size: 1em; |
||||
clear: both; |
||||
color: #333; |
||||
} |
||||
|
||||
.login .form-row #id_username, .login .form-row #id_password { |
||||
clear: both; |
||||
padding: 8px; |
||||
width: 100%; |
||||
-webkit-box-sizing: border-box; |
||||
-moz-box-sizing: border-box; |
||||
box-sizing: border-box; |
||||
} |
||||
|
||||
.login span.help { |
||||
font-size: 10px; |
||||
display: block; |
||||
} |
||||
|
||||
.login .submit-row { |
||||
clear: both; |
||||
padding: 1em 0 0 9.4em; |
||||
margin: 0; |
||||
border: none; |
||||
background: none; |
||||
text-align: left; |
||||
} |
||||
|
||||
.login .password-reset-link { |
||||
text-align: center; |
||||
} |
||||
Binary file not shown.
@ -1,78 +0,0 @@ |
||||
/* LOGIN FORM */ |
||||
|
||||
body.login { |
||||
background: #f8f8f8; |
||||
} |
||||
|
||||
.login #header { |
||||
height: auto; |
||||
padding: 5px 16px; |
||||
} |
||||
|
||||
.login #header h1 { |
||||
font-size: 18px; |
||||
} |
||||
|
||||
.login #header h1 a { |
||||
color: #fff; |
||||
} |
||||
|
||||
.login #content { |
||||
padding: 20px 20px 0; |
||||
} |
||||
|
||||
.login #container { |
||||
background: #fff; |
||||
border: 1px solid #eaeaea; |
||||
border-radius: 4px; |
||||
overflow: hidden; |
||||
width: 28em; |
||||
min-width: 300px; |
||||
margin: 100px auto; |
||||
} |
||||
|
||||
.login #content-main { |
||||
width: 100%; |
||||
} |
||||
|
||||
.login .form-row { |
||||
padding: 4px 0; |
||||
float: left; |
||||
width: 100%; |
||||
border-bottom: none; |
||||
} |
||||
|
||||
.login .form-row label { |
||||
padding-right: 0.5em; |
||||
line-height: 2em; |
||||
font-size: 1em; |
||||
clear: both; |
||||
color: #333; |
||||
} |
||||
|
||||
.login .form-row #id_username, .login .form-row #id_password { |
||||
clear: both; |
||||
padding: 8px; |
||||
width: 100%; |
||||
-webkit-box-sizing: border-box; |
||||
-moz-box-sizing: border-box; |
||||
box-sizing: border-box; |
||||
} |
||||
|
||||
.login span.help { |
||||
font-size: 10px; |
||||
display: block; |
||||
} |
||||
|
||||
.login .submit-row { |
||||
clear: both; |
||||
padding: 1em 0 0 9.4em; |
||||
margin: 0; |
||||
border: none; |
||||
background: none; |
||||
text-align: left; |
||||
} |
||||
|
||||
.login .password-reset-link { |
||||
text-align: center; |
||||
} |
||||
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue