Compare commits
18 Commits
Author | SHA1 | Date |
---|---|---|
Fred Pauchet | c6e23e3e9b | |
Fred Pauchet | 78b7cbe7c8 | |
Fred Pauchet | ad41c0c025 | |
Fred Pauchet | 23214c70fa | |
jaguarondi | 95cf14c5df | |
jaguarondi | ce3684fe67 | |
Declerfayt Cedric | 52063691bb | |
Declerfayt Cedric | cb2d0df5cf | |
Fred | c5712a1401 | |
Fred Pauchet | a121b293ff | |
Fred Pauchet | cb505662da | |
Fred | 90e333d9c4 | |
Fred | 95693e2781 | |
Fred | 26e96ce5a6 | |
Fred | a46a484b85 | |
Fred | 1c3867367d | |
Fred | 7147a8e63c | |
Fred Pauchet | 52dfe7cada |
|
@ -1,7 +1,7 @@
|
|||
# .coveragerc to control coverage.py
|
||||
[run]
|
||||
branch = True
|
||||
omit = ../*migrations*
|
||||
omit = *migrations*, *manage.py
|
||||
|
||||
[report]
|
||||
ignore_errors = True
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
pipeline:
|
||||
build:
|
||||
image: python:3
|
||||
commands:
|
||||
- pip install --no-cache-dir -r requirements/base.txt
|
||||
- python manage.py check
|
|
@ -3,3 +3,5 @@ __pycache__
|
|||
*.*~
|
||||
migrations
|
||||
.coverage
|
||||
coverage_html_report/
|
||||
.vscode/*
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
before_script:
|
||||
- pip install -r requirements/dev.txt
|
||||
|
||||
test:python-3.4:
|
||||
stage: test
|
||||
image: python:3.4-slim
|
||||
script:
|
||||
- flake8 src/
|
||||
- coverage run src/manage.py test wish
|
||||
- coverage report -m
|
||||
|
4
Makefile
4
Makefile
|
@ -12,5 +12,7 @@ help:
|
|||
@echo " coverage to run coverage check of the source files."
|
||||
|
||||
coverage:
|
||||
coverage run --source='gwift' gwift/manage.py test; coverage report; coverage html;
|
||||
cd src; coverage run --rcfile='../.coveragerc' --source='.' manage.py test;
|
||||
cd src; coverage report --rcfile='../.coveragerc';
|
||||
cd src; coverage html --rcfile='../.coveragerc';
|
||||
@echo "Testing of coverage in the sources finished."
|
|
@ -0,0 +1,2 @@
|
|||
|
||||
[![Build Status](https://drone.grimbox.be/api/badges/fred/gwift/status.svg)](https://drone.grimbox.be/fred/gwift)
|
|
@ -1,5 +1,5 @@
|
|||
try:
|
||||
from .local import *
|
||||
from .local import * # NOQA
|
||||
except ImportError:
|
||||
# Dev env by defautl if no local file proviced
|
||||
from .dev import *
|
||||
from .dev import * # NOQA
|
|
@ -31,10 +31,10 @@ INSTALLED_APPS = (
|
|||
'django.contrib.sessions',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
'wish',
|
||||
'gwift.wish',
|
||||
)
|
||||
|
||||
MIDDLEWARE_CLASSES = (
|
||||
MIDDLEWARE = (
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
'django.middleware.csrf.CsrfViewMiddleware',
|
||||
|
@ -50,7 +50,7 @@ ROOT_URLCONF = 'gwift.urls'
|
|||
TEMPLATES = [
|
||||
{
|
||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||
'DIRS': [ 'templates' ],
|
||||
'DIRS': ['templates'],
|
||||
'APP_DIRS': True,
|
||||
'OPTIONS': {
|
||||
'context_processors': [
|
||||
|
@ -65,8 +65,6 @@ TEMPLATES = [
|
|||
|
||||
WSGI_APPLICATION = 'gwift.wsgi.application'
|
||||
|
||||
|
||||
|
||||
# Internationalization
|
||||
# https://docs.djangoproject.com/en/1.8/topics/i18n/
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
from .base import *
|
||||
from .base import * # NOQA
|
||||
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = True
|
||||
|
@ -8,7 +8,7 @@ SECRET_KEY = '5r4-zjux*_p7@^()pc+0sv(6rc@_vdjmce#!5!tx&qx7)opu$7'
|
|||
|
||||
for template_engine in TEMPLATES:
|
||||
template_engine['OPTIONS']['debug'] = True
|
||||
|
||||
|
||||
'''INSTALLED_APPS += [
|
||||
'debug_toolbar',
|
||||
]'''
|
||||
|
@ -26,4 +26,8 @@ DATABASES = {
|
|||
'ENGINE': 'django.db.backends.sqlite3',
|
||||
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
STATICFILES_DIRS = [
|
||||
os.path.join(BASE_DIR, "static"),
|
||||
]
|
|
@ -1,4 +1,4 @@
|
|||
from .base import *
|
||||
from .base import * # NOQA
|
||||
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = False
|
||||
|
@ -26,4 +26,3 @@ CSRF_COOKIE_SECURE = True
|
|||
|
||||
# Same for session cookie
|
||||
SESSION_COOKIE_SECURE = True
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="x-ua-compatible" content="ie=edge">
|
||||
<title></title>
|
||||
</head>
|
||||
<body>
|
||||
<p>Mes listes de souhaits</p>
|
||||
<ul>
|
||||
{% for wishlist in wishlists %}
|
||||
<li>{{ wishlist.name }}: {{ wishlist.description }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
|
@ -15,12 +15,12 @@ Including another URLconf
|
|||
1. Add an import: from blog import urls as blog_urls
|
||||
2. Add a URL to urlpatterns: url(r'^blog/', include(blog_urls))
|
||||
"""
|
||||
from django.conf.urls import include, url
|
||||
from django.conf.urls import include
|
||||
from django.urls import path
|
||||
from django.contrib import admin
|
||||
|
||||
from wish.views import WishListList
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^admin/', include(admin.site.urls)),
|
||||
url(r'^$', WishListList.as_view(), name='wishlists'),
|
||||
path(r'^admin/', admin.site.urls),
|
||||
path(r'^', include('gwift.wish.urls'))
|
||||
]
|
|
@ -1,3 +1,8 @@
|
|||
from django.contrib import admin
|
||||
|
||||
from .models import Wishlist, Wish, WishPart
|
||||
|
||||
# Register your models here.
|
||||
admin.site.register(Wishlist)
|
||||
admin.site.register(Wish)
|
||||
admin.site.register(WishPart)
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import uuid
|
||||
|
||||
from django.db import models
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
import uuid
|
||||
|
||||
|
||||
class AbstractModel(models.Model):
|
||||
class Meta:
|
||||
|
@ -11,10 +11,12 @@ class AbstractModel(models.Model):
|
|||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
|
||||
|
||||
class UnknownUser(models.Model):
|
||||
|
||||
name = models.CharField(max_length=255)
|
||||
email = models.CharField(max_length=255)
|
||||
email = models.CharField(max_length=255, unique=True)
|
||||
|
||||
|
||||
class Wishlist(AbstractModel):
|
||||
|
||||
|
@ -22,18 +24,14 @@ class Wishlist(AbstractModel):
|
|||
description = models.TextField()
|
||||
external_id = models.UUIDField(unique=True, default=uuid.uuid4, editable=False)
|
||||
|
||||
@staticmethod
|
||||
def create(name, description):
|
||||
w = Wishlist()
|
||||
w.name = name
|
||||
w.description = description
|
||||
w.save()
|
||||
return w
|
||||
|
||||
|
||||
class Wish(AbstractModel):
|
||||
|
||||
wishlist = models.ForeignKey(Wishlist, related_name='items')
|
||||
wishlist = models.ForeignKey(
|
||||
Wishlist,
|
||||
related_name='items',
|
||||
on_delete=models.DO_NOTHING
|
||||
)
|
||||
name = models.CharField(max_length=255)
|
||||
description = models.TextField()
|
||||
picture = models.ImageField(null=True)
|
||||
|
@ -42,31 +40,23 @@ class Wish(AbstractModel):
|
|||
estimated_price = models.DecimalField(max_digits=19, decimal_places=2,
|
||||
null=True)
|
||||
|
||||
@staticmethod
|
||||
def create(name, description, wishlist):
|
||||
i = Wish()
|
||||
i.name = name
|
||||
i.description = description
|
||||
i.wishlist = wishlist
|
||||
i.save()
|
||||
return i
|
||||
|
||||
@property
|
||||
def percentage(self):
|
||||
"""
|
||||
Calcule le pourcentage de complétion pour un élément.
|
||||
"""
|
||||
number_of_linked_parts = Part.objects.filter(wish=self).count()
|
||||
def percentage_of_completion(self):
|
||||
"""Calcule le pourcentage de complétion pour un élément."""
|
||||
|
||||
number_of_linked_parts = WishPart.objects.filter(wish=self).count()
|
||||
total = self.number_of_parts * self.numbers_available
|
||||
percentage = (number_of_linked_parts / total)
|
||||
return percentage * 100
|
||||
|
||||
class WishPart(models.Model):
|
||||
wish = models.ForeignKey(Wish)
|
||||
user = models.ForeignKey(User)
|
||||
unknown_user = models.ForeignKey('UnknownUser')
|
||||
comment = models.TextField()
|
||||
done_at = models.DateTimeField()
|
||||
|
||||
def save(self, force_insert=False, force_update=False, commit=True):
|
||||
def get_absolute_url(self):
|
||||
pass
|
||||
|
||||
|
||||
class WishPart(models.Model):
|
||||
|
||||
wish = models.ForeignKey(Wish, on_delete=models.DO_NOTHING)
|
||||
user = models.ForeignKey(User, null=True, on_delete=models.DO_NOTHING)
|
||||
unknown_user = models.ForeignKey('UnknownUser', null=True, on_delete=models.DO_NOTHING)
|
||||
comment = models.TextField(null=True, blank=True)
|
||||
done_at = models.DateTimeField(auto_now_add=True)
|
||||
|
|
|
@ -1,19 +1,24 @@
|
|||
# coding=utf-8
|
||||
|
||||
import datetime
|
||||
|
||||
from django import template
|
||||
|
||||
from wish.models import Wishlist
|
||||
from gwift.wish.models import Wishlist
|
||||
|
||||
register = template.Library()
|
||||
|
||||
|
||||
@register.filter(is_safe=True)
|
||||
def add_xx(value):
|
||||
return '%sxx' % value
|
||||
|
||||
|
||||
@register.simple_tag
|
||||
def current_time(format_string):
|
||||
return datetime.datetime.now().strftime(format_string)
|
||||
|
||||
|
||||
@register.inclusion_tag('wish/templatetags/wishlists_list.html')
|
||||
def wishlists_list():
|
||||
return { 'list': Wishlist.objects.all() }
|
||||
return {'list': Wishlist.objects.all()}
|
||||
|
|
|
@ -1,3 +1,36 @@
|
|||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
from .models import Wishlist, Wish, WishPart
|
||||
|
||||
|
||||
class TestWishModel(TestCase):
|
||||
def test_percentage_of_completion(self):
|
||||
"""
|
||||
Vérifie que le pourcentage de complétion d'un souhait
|
||||
est correctement calculé.
|
||||
"""
|
||||
wishlist = Wishlist(name='Fake WishList',
|
||||
description='This is a faked wishlist')
|
||||
wishlist.save()
|
||||
|
||||
wish = Wish(wishlist=wishlist,
|
||||
name='Fake Wish',
|
||||
description='This is a faked wish',
|
||||
number_of_parts=4)
|
||||
wish.save()
|
||||
|
||||
part1 = WishPart(wish=wish, comment='part1')
|
||||
part1.save()
|
||||
self.assertEqual(25, wish.percentage_of_completion)
|
||||
|
||||
part2 = WishPart(wish=wish, comment='part2')
|
||||
part2.save()
|
||||
self.assertEqual(50, wish.percentage_of_completion)
|
||||
|
||||
part3 = WishPart(wish=wish, comment='part3')
|
||||
part3.save()
|
||||
self.assertEqual(75, wish.percentage_of_completion)
|
||||
|
||||
part4 = WishPart(wish=wish, comment='part4')
|
||||
part4.save()
|
||||
self.assertEqual(100, wish.percentage_of_completion)
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
# gwift/urls.py
|
||||
|
||||
"""gwift URL Configuration
|
||||
|
||||
The `urlpatterns` list routes URLs to views. For more information please see:
|
||||
https://docs.djangoproject.com/en/1.8/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. Add an import: from blog import urls as blog_urls
|
||||
2. Add a URL to urlpatterns: url(r'^blog/', include(blog_urls))
|
||||
"""
|
||||
from django.conf.urls import url
|
||||
|
||||
from .views import WishListList, WishListDetail, WishDetail, UpdateWishView
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^$', WishListList.as_view(), name='wishlists'),
|
||||
url(r'^list/(?P<pk>\d+)/$', WishListDetail.as_view(), name='wishlist'),
|
||||
url(r'^wish/(?P<pk>\d+)/$', WishDetail.as_view(), name='wish'),
|
||||
url(r'^wish/(?P<pk>\d+)/edit$', UpdateWishView.as_view(), name='wish-edit'),
|
||||
]
|
|
@ -1,10 +1,27 @@
|
|||
# wish/views.py
|
||||
|
||||
from django.views.generic import ListView
|
||||
from django.views.generic import ListView, DetailView, UpdateView
|
||||
|
||||
from .models import Wish, Wishlist
|
||||
|
||||
from .models import Wishlist
|
||||
|
||||
class WishListList(ListView):
|
||||
context_object_name = 'wishlists'
|
||||
model = Wishlist
|
||||
template_name = 'wish/list.html'
|
||||
|
||||
class WishListDetail(DetailView):
|
||||
context_object_name = 'wishlist'
|
||||
model = Wishlist
|
||||
template_name = 'wish/list_detail.html'
|
||||
|
||||
class WishDetail(DetailView):
|
||||
context_object_name = 'wish'
|
||||
model = Wish
|
||||
template_name = 'wish/wish_detail.html'
|
||||
|
||||
class UpdateWishView(UpdateView):
|
||||
model = Wish
|
||||
fields = ('name', 'description')
|
||||
template_name = 'wish/wish_update.html'
|
||||
|
||||
|
|
|
@ -3,7 +3,5 @@
|
|||
flake8
|
||||
mccabe
|
||||
pep8
|
||||
django-nose
|
||||
nose
|
||||
django_coverage_plugin
|
||||
coverage
|
||||
pyflakes
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
[flake8]
|
||||
max-line-length = 120
|
||||
exclude = .tox,.git,*/migrations/*,*/static/CACHE/*,docs,node_modules
|
||||
max-complexity = 6
|
||||
|
||||
[pep8]
|
||||
max-line-length = 120
|
||||
exclude=.tox,.git,*/migrations/*,*/static/CACHE/*,docs,node_modules
|
|
@ -0,0 +1,82 @@
|
|||
html {
|
||||
position: relative;
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Open Sans', sans-serif;
|
||||
/* Margin bottom by footer height */
|
||||
margin-bottom: 4em;
|
||||
}
|
||||
|
||||
.user-avatar {
|
||||
width: 1.5em;
|
||||
height: 1.5em;
|
||||
border-radius: .75em;
|
||||
}
|
||||
|
||||
.slimg {
|
||||
width: auto;
|
||||
height: 270px;
|
||||
max-height: 270px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.project-card-description {
|
||||
height: 3em;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.base-header {
|
||||
width: 100%;
|
||||
max-height: 200px;
|
||||
margin-top: 5px;
|
||||
vertical-align: bottom;
|
||||
}
|
||||
|
||||
#nav.affix {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
z-index:10;
|
||||
}
|
||||
|
||||
.nav-wrapper
|
||||
{
|
||||
min-height:70px;
|
||||
}
|
||||
|
||||
#home-logo {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
background-image:linear-gradient(white, #BBBBBB);
|
||||
}
|
||||
|
||||
#home-logo-image {
|
||||
width: 50%;
|
||||
margin: auto;
|
||||
height: auto;
|
||||
max-height: 120px;
|
||||
max-width: 243px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.navbar-shadow{
|
||||
-webkit-box-shadow: 0px 9px 43px -4px rgba(61,61,61,0.5);
|
||||
-moz-box-shadow: 0px 9px 43px -4px rgba(61,61,61,0.5);
|
||||
box-shadow: 0px 9px 43px -4px rgba(61,61,61,0.5);
|
||||
}
|
||||
|
||||
.footer {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
/*Set the fixed height of the footer here */
|
||||
height: 4em;
|
||||
padding-top: 1em;
|
||||
border-top: 1px solid #f5f5f5;
|
||||
}
|
||||
|
||||
.footer a {
|
||||
color: #5b94c5;
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 657 B |
Binary file not shown.
After Width: | Height: | Size: 570 B |
|
@ -0,0 +1,5 @@
|
|||
$('#nav').affix({
|
||||
offset: {
|
||||
top: $('header').height()
|
||||
}
|
||||
});
|
|
@ -0,0 +1,3 @@
|
|||
<div class="container">
|
||||
Copylefted '16
|
||||
</div>
|
|
@ -0,0 +1,14 @@
|
|||
<ul class="nav navbar-nav">
|
||||
<li class="">
|
||||
<a href="#">
|
||||
<i class="fa fa-calendar"></i> Mes listes
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
<li class="">
|
||||
<a href="#">
|
||||
<i class="fa fa-user"></i> Login / Register
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
|
@ -0,0 +1,64 @@
|
|||
{% load staticfiles %}
|
||||
|
||||
<!DOCTYPE html>
|
||||
<!--[if IE 9]><html class="lt-ie10" lang="en" > <![endif]-->
|
||||
<html class="no-js" lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet">
|
||||
<script src="//code.jquery.com/jquery.min.js"></script>
|
||||
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
|
||||
<link href='https://fonts.googleapis.com/css?family=Open+Sans' rel='stylesheet' type='text/css'>
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css">
|
||||
<link href="{% static 'css/style.css' %}" rel="stylesheet">
|
||||
<link rel="icon" href="{% static 'img/favicon.ico' %}" />
|
||||
<title>Gwift</title>
|
||||
</head>
|
||||
|
||||
<body class="base-body">
|
||||
|
||||
<!-- navigation -->
|
||||
<div class="nav-wrapper">
|
||||
<div id="nav">
|
||||
<nav class="navbar navbar-default navbar-static-top navbar-shadow">
|
||||
<div class="container-fluid">
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#menuNavbar">
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<a class="navbar-brand" href="/">
|
||||
<img src="{% static 'img/gwift-20x20.png' %}" />
|
||||
</a>
|
||||
</div>
|
||||
<div class="collapse navbar-collapse" id="menuNavbar">
|
||||
{% include "_menu_items.html" %}
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
<!-- end navigation -->
|
||||
|
||||
<!-- content -->
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
{% block content %}{% endblock %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- end content -->
|
||||
|
||||
<!-- footer -->
|
||||
<footer class="footer">
|
||||
{% include "_footer.html" %}
|
||||
</footer>
|
||||
<!-- end footer -->
|
||||
|
||||
<!--<script src="/static/js/navbar.js"></script>-->
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,11 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<p>Mes listes de souhaits</p>
|
||||
<ul>
|
||||
{% for wishlist in wishlists %}
|
||||
<li><a href="{% url "wish:wishlist" wishlist.pk %}">{{ wishlist.name }}</a>: {{ wishlist.description }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endblock %}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<h3>Liste {{ wishlist.name }}</h3>
|
||||
<div>
|
||||
{{ wishlist.description }}
|
||||
</div>
|
||||
<div>
|
||||
<ul>
|
||||
{% for wish in wishlist.items.all %}
|
||||
<li><a href="{% url "wish:wish" wish.pk %}">{{ wish.name }}</a>: {{ wish.description }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<h3>{{ wish.name }}</h3>
|
||||
<div>
|
||||
{{ wish.description }}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<h3>Editer {{ wish.name }}</h3>
|
||||
<form action="{{ action }}" method="POST">
|
||||
{% csrf_token %}
|
||||
<ul>
|
||||
{{ form.as_ul }}
|
||||
</ul>
|
||||
<input id="save_wish" type="submit" value="Save" />
|
||||
</form>
|
||||
|
||||
{% endblock %}
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
#!/bin/bash
|
||||
|
||||
WORK_DIR="$(dirname "$0")"
|
||||
DISTRO_NAME=$(lsb_release -sc)
|
||||
OS_REQUIREMENTS_FILENAME="requirements-$DISTRO_NAME.apt"
|
||||
|
||||
cd $WORK_DIR
|
||||
|
||||
# Check if a requirements file exist for the current distribution.
|
||||
if [ ! -r "$OS_REQUIREMENTS_FILENAME" ]; then
|
||||
cat <<-EOF >&2
|
||||
There is no requirements file for your distribution.
|
||||
You can see one of the files listed below to help search the equivalent package in your system:
|
||||
$(find ./ -name "requirements-*.apt" -printf " - %f\n")
|
||||
EOF
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
# Handle call with wrong command
|
||||
function wrong_command()
|
||||
{
|
||||
echo "${0##*/} - unknown command: '${1}'" >&2
|
||||
usage_message
|
||||
}
|
||||
|
||||
# Print help / script usage
|
||||
function usage_message()
|
||||
{
|
||||
cat <<-EOF
|
||||
Usage: $WORK_DIR/${0##*/} <command>
|
||||
Available commands are:
|
||||
list Print a list of all packages defined on ${OS_REQUIREMENTS_FILENAME} file
|
||||
help Print this help
|
||||
|
||||
Commands that require superuser permission:
|
||||
install Install packages defined on ${OS_REQUIREMENTS_FILENAME} file. Note: This
|
||||
does not upgrade the packages already installed for new versions, even if
|
||||
new version is available in the repository.
|
||||
upgrade Same that install, but upgrade the already installed packages, if new
|
||||
version is available.
|
||||
EOF
|
||||
}
|
||||
|
||||
# Read the requirements.apt file, and remove comments and blank lines
|
||||
function list_packages(){
|
||||
grep -v "#" "${OS_REQUIREMENTS_FILENAME}" | grep -v "^$";
|
||||
}
|
||||
|
||||
function install_packages()
|
||||
{
|
||||
list_packages | xargs apt-get --no-upgrade install -y;
|
||||
}
|
||||
|
||||
function upgrade_packages()
|
||||
{
|
||||
list_packages | xargs apt-get install -y;
|
||||
}
|
||||
|
||||
function install_or_upgrade()
|
||||
{
|
||||
P=${1}
|
||||
PARAN=${P:-"install"}
|
||||
|
||||
if [[ $EUID -ne 0 ]]; then
|
||||
cat <<-EOF >&2
|
||||
You must run this script with root privilege
|
||||
Please do:
|
||||
sudo $WORK_DIR/${0##*/} $PARAN
|
||||
EOF
|
||||
exit 1
|
||||
else
|
||||
|
||||
apt-get update
|
||||
|
||||
# Install the basic compilation dependencies and other required libraries of this project
|
||||
if [ "$PARAN" == "install" ]; then
|
||||
install_packages;
|
||||
else
|
||||
upgrade_packages;
|
||||
fi
|
||||
|
||||
# cleaning downloaded packages from apt-get cache
|
||||
apt-get clean
|
||||
|
||||
exit 0
|
||||
fi
|
||||
}
|
||||
|
||||
# Handle command argument
|
||||
case "$1" in
|
||||
install) install_or_upgrade;;
|
||||
upgrade) install_or_upgrade "upgrade";;
|
||||
list) list_packages;;
|
||||
help|"") usage_message;;
|
||||
*) wrong_command "$1";;
|
||||
esac
|
|
@ -0,0 +1,44 @@
|
|||
#!/bin/bash
|
||||
|
||||
WORK_DIR="$(dirname "$0")"
|
||||
PROJECT_DIR="$(dirname "$WORK_DIR")"
|
||||
|
||||
pip --version >/dev/null 2>&1 || {
|
||||
echo >&2 -e "\npip is required but it's not installed."
|
||||
echo >&2 -e "You can install it by running the following command:\n"
|
||||
echo >&2 "wget https://bootstrap.pypa.io/get-pip.py --output-document=get-pip.py; chmod +x get-pip.py; sudo -H python3 get-pip.py"
|
||||
|
||||
echo >&2 -e "\n"
|
||||
echo >&2 -e "\nFor more information, see pip documentation: https://pip.pypa.io/en/latest/"
|
||||
exit 1;
|
||||
}
|
||||
|
||||
virtualenv --version >/dev/null 2>&1 || {
|
||||
echo >&2 -e "\nvirtualenv is required but it's not installed."
|
||||
echo >&2 -e "You can install it by running the following command:\n"
|
||||
echo >&2 "sudo -H pip3 install virtualenv"
|
||||
|
||||
echo >&2 -e "\n"
|
||||
echo >&2 -e "\nFor more information, see virtualenv documentation: https://virtualenv.pypa.io/en/latest/"
|
||||
exit 1;
|
||||
}
|
||||
|
||||
if [ -z "$VIRTUAL_ENV" ]; then
|
||||
echo >&2 -e "\nYou need activate a virtualenv first"
|
||||
echo >&2 -e 'If you do not have a virtualenv created, run the following command to create and automatically activate a new virtualenv named "venv" on current folder:\n'
|
||||
echo >&2 -e "virtualenv venv --python=\`which python3\`"
|
||||
|
||||
echo >&2 -e "\nTo leave/disable the currently active virtualenv, run the following command:\n"
|
||||
echo >&2 "deactivate"
|
||||
echo >&2 -e "\nTo activate the virtualenv again, run the following command:\n"
|
||||
echo >&2 "source venv/bin/activate"
|
||||
echo >&2 -e "\nFor more information, see virtualenv documentation: https://virtualenv.pypa.io/en/latest/"
|
||||
echo >&2 -e "\n"
|
||||
exit 1;
|
||||
else
|
||||
|
||||
pip install -r $PROJECT_DIR/requirements/local.txt
|
||||
pip install -r $PROJECT_DIR/requirements/test.txt
|
||||
pip install -r $PROJECT_DIR/requirements.txt
|
||||
fi
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
##basic build dependencies of various Django apps for Debian Jessie 8.x
|
||||
#build-essential metapackage install: make, gcc, g++,
|
||||
build-essential
|
||||
#required to translate
|
||||
gettext
|
||||
python3-dev
|
||||
|
||||
|
||||
##shared dependencies of:
|
||||
##Pillow, pylibmc
|
||||
zlib1g-dev
|
||||
|
||||
##Postgresql and psycopg2 dependencies
|
||||
libpq-dev
|
||||
|
||||
##Pillow dependencies
|
||||
libtiff5-dev
|
||||
libjpeg62-turbo-dev
|
||||
libfreetype6-dev
|
||||
liblcms2-dev
|
||||
libwebp-dev
|
||||
|
||||
##django-extensions
|
||||
graphviz-dev
|
|
@ -0,0 +1,24 @@
|
|||
##basic build dependencies of various Django apps for Debian Jessie 8.x
|
||||
#build-essential metapackage install: make, gcc, g++,
|
||||
build-essential
|
||||
#required to translate
|
||||
gettext
|
||||
python3-dev
|
||||
|
||||
|
||||
##shared dependencies of:
|
||||
##Pillow, pylibmc
|
||||
zlib1g-dev
|
||||
|
||||
##Postgresql and psycopg2 dependencies
|
||||
libpq-dev
|
||||
|
||||
##Pillow dependencies
|
||||
libtiff5-dev
|
||||
libjpeg62-turbo-dev
|
||||
libfreetype6-dev
|
||||
liblcms2-dev
|
||||
libwebp-dev
|
||||
|
||||
##django-extensions
|
||||
graphviz-dev
|
|
@ -0,0 +1,25 @@
|
|||
##basic build dependencies of various Django apps for Ubuntu Trusty 14.04
|
||||
#build-essential metapackage install: make, gcc, g++,
|
||||
build-essential
|
||||
#required to translate
|
||||
gettext
|
||||
python3-dev
|
||||
|
||||
|
||||
##shared dependencies of:
|
||||
##Pillow, pylibmc
|
||||
zlib1g-dev
|
||||
|
||||
##Postgresql and psycopg2 dependencies
|
||||
libpq-dev
|
||||
|
||||
##Pillow dependencies
|
||||
libtiff4-dev
|
||||
libjpeg8-dev
|
||||
libfreetype6-dev
|
||||
liblcms1-dev
|
||||
libwebp-dev
|
||||
|
||||
##django-extensions
|
||||
graphviz-dev
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
##basic build dependencies of various Django apps for Ubuntu Xenial 16.04
|
||||
#build-essential metapackage install: make, gcc, g++,
|
||||
build-essential
|
||||
#required to translate
|
||||
gettext
|
||||
python3-dev
|
||||
|
||||
|
||||
##shared dependencies of:
|
||||
##Pillow, pylibmc
|
||||
zlib1g-dev
|
||||
|
||||
##Postgresql and psycopg2 dependencies
|
||||
libpq-dev
|
||||
|
||||
##Pillow dependencies
|
||||
libtiff5-dev
|
||||
libjpeg8-dev
|
||||
libfreetype6-dev
|
||||
liblcms2-dev
|
||||
libwebp-dev
|
||||
|
||||
##django-extensions
|
||||
graphviz-dev
|
||||
|
Loading…
Reference in New Issue