Skip to content
Extraits de code Groupes Projets

Comparer les révisions

Les modifications sont affichées comme si la révision source était fusionnée avec la révision cible. En savoir plus sur la comparaison des révisions.

Source

Sélectionner le projet cible
No results found

Cible

Sélectionner le projet cible
  • la-quadrature-du-net/memopol/memopol
  • lnclt/political_memory
  • arthur/political_memory
  • agrausem/political_memory
  • periode/memopol
  • Anthony/memopol
  • Porkepix/memopol
  • jaster/memopol
  • luxcem/memopol
  • TAlone/memopol
10 résultats
Afficher les modifications
Affichage de
avec 0 ajout et 1058 suppressions
# coding: utf-8
# This file is part of memopol.
#
# memopol is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of
# the License, or any later version.
#
# memopol is distributed in the hope that it will
# be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU General Affero Public
# License along with django-representatives.
# If not, see <http://www.gnu.org/licenses/>.
#
# Copyright (C) 2015 Arnaud Fabre <af@laquadrature.net>
from django.conf.urls import url
from views import representative
from views import group
urlpatterns = [
# List of groups by group kind
url(
r'^groups/(?P<kind>\w+)?$',
group.index,
name='group-index'
),
# Representative detail by representative name
url(
r'^(?P<name>[-\w]+)$',
representative.detail,
name='representative-detail'
),
# Representative detail by representative pk
url(
r'^(?P<pk>\d+)$',
representative.detail,
name='representative-detail'
),
# List of representatives by group kind and group name or pk
url(
r'^(?P<group_kind>\w+)/(?P<group>.+)$',
representative.index,
name='representative-index'
),
# List all representatives by default
url(
r'',
representative.index,
name='representative-index'
),
]
# coding: utf-8
# This file is part of memopol.
#
# memopol is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of
# the License, or any later version.
#
# memopol is distributed in the hope that it will
# be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU General Affero Public
# License along with django-representatives.
# If not, see <http://www.gnu.org/licenses/>.
#
# Copyright (C) 2015 Arnaud Fabre <af@laquadrature.net>
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.shortcuts import render
def render_paginate_list(request, object_list, template_name, num_by_page=30):
"""
Render a paginated list of representatives
"""
paginator = Paginator(object_list, num_by_page)
page = request.GET.get('page')
try:
objects = paginator.page(page)
except PageNotAnInteger:
objects = paginator.page(1)
except EmptyPage:
objects = paginator.page(paginator.num_pages)
context = {}
queries_without_page = request.GET.copy()
if 'page' in queries_without_page:
del queries_without_page['page']
context['queries'] = queries_without_page
context['object_list'] = objects
context['object_count'] = paginator.count
return render(
request,
template_name,
context
)
# coding: utf-8
# This file is part of memopol.
#
# memopol is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of
# the License, or any later version.
#
# memopol is distributed in the hope that it will
# be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU General Affero Public
# License along with django-representatives.
# If not, see <http://www.gnu.org/licenses/>.
#
# Copyright (C) 2015 Arnaud Fabre <af@laquadrature.net>
from datetime import datetime
from django.shortcuts import render
from representatives.models import Group
def index(request, kind=None):
groups = Group.objects.filter(
mandates__end_date__gte=datetime.now()
)
if kind:
groups = groups.filter(
kind=kind
)
groups = groups.distinct().order_by('name')
return render(
request,
'legislature/groups_list.html',
{'groups': groups}
)
# coding: utf-8
# This file is part of memopol.
#
# memopol is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of
# the License, or any later version.
#
# memopol is distributed in the hope that it will
# be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU General Affero Public
# License along with django-representatives.
# If not, see <http://www.gnu.org/licenses/>.
#
# Copyright (C) 2015 Arnaud Fabre <af@laquadrature.net>
from __future__ import absolute_import
from datetime import datetime
from django.shortcuts import render
from django.db.models import Q
from django.http import Http404
from ..models import MemopolRepresentative
from core.utils import render_paginate_list
from positions.forms import PositionForm
def index(request, group_kind=None, group=None):
# Fetch active representatives
representative_list = MemopolRepresentative.objects.select_related(
'country',
'main_mandate',
'main_mandate__group',
).filter(
active=True
)
# Filter the list by group if group information is provided
if group_kind:
if group.isnumeric():
representative_list = representative_list.filter(
mandates__group_id=int(group),
mandates__end_date__gte=datetime.now()
)
else:
# Search group based on abbreviation or name
representative_list = representative_list.filter(
Q(mandates__group__abbreviation=group) |
Q(mandates__group__name=group),
mandates__group__kind=group_kind,
mandates__end_date__gte=datetime.now()
)
# Filter the list by search
representative_list = _filter_by_search(
request,
representative_list
).order_by('-score', 'last_name')
# Render the paginated template
return render_paginate_list(
request,
representative_list,
'legislature/representative_list.html'
)
def detail(request, pk=None, name=None):
try:
query_set = MemopolRepresentative.objects.select_related(
'country',
'main_mandate'
)
if pk:
representative = query_set.get(
id=pk
)
elif name:
representative = query_set.get(
slug=name
)
else:
return Http404()
except MemopolRepresentative.DoesNotExist:
return Http404()
position_form = PositionForm()
return render(
request,
'legislature/representative_detail.html',
{
'representative': representative,
'position_form': position_form
}
)
def _filter_by_search(request, representative_list):
"""
Return a representative_list filtered by
the representative name provided in search form
"""
search = request.GET.get('search')
if search:
return representative_list.filter(
Q(full_name__icontains=search)
)
else:
return representative_list
# coding: utf-8
# This file is part of memopol.
#
# memopol is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of
# the License, or any later version.
#
# memopol is distributed in the hope that it will
# be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU General Affero Public
# License along with django-representatives.
# If not, see <http://www.gnu.org/licenses/>.
#
# Copyright (C) 2015 Arnaud Fabre <af@laquadrature.net>
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.shortcuts import render
def render_paginate_list(request, object_list, template_name, num_by_page=30):
"""
Render a paginated list of representatives
"""
paginator = Paginator(object_list, num_by_page)
page = request.GET.get('page')
try:
objects = paginator.page(page)
except PageNotAnInteger:
objects = paginator.page(1)
except EmptyPage:
objects = paginator.page(paginator.num_pages)
context = {}
queries_without_page = request.GET.copy()
if 'page' in queries_without_page:
del queries_without_page['page']
context['queries'] = queries_without_page
context['object_list'] = objects
context['object_count'] = paginator.count
return render(
request,
template_name,
context
)
# coding: utf-8
# This file is part of memopol.
#
# memopol is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of
# the License, or any later version.
#
# memopol is distributed in the hope that it will
# be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU General Affero Public
# License along with django-representatives.
# If not, see <http://www.gnu.org/licenses/>.
#
# Copyright (C) 2015 Arnaud Fabre <af@laquadrature.net>
from __future__ import absolute_import
# This will make sure the app is always imported when
# Django starts so that shared_task will use this app.
from .celery import app as celery_app
# coding: utf-8
# This file is part of memopol.
#
# memopol is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of
# the License, or any later version.
#
# memopol is distributed in the hope that it will
# be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU General Affero Public
# License along with django-representatives.
# If not, see <http://www.gnu.org/licenses/>.
#
# Copyright (C) 2015 Arnaud Fabre <af@laquadrature.net>
from __future__ import absolute_import
import os
from django.conf import settings
from celery import Celery
# set the default Django settings module for the 'celery' program.
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'memopol.settings')
app = Celery(
'memopol',
broker='redis://localhost/{}'.format(settings.REDIS_DB),
backend='redis://localhost/{}'.format(settings.REDIS_DB)
)
# Using a string here means the worker will not have to
# pickle the object when using Windows.
app.config_from_object('django.conf:settings')
app.autodiscover_tasks(lambda: settings.INSTALLED_APPS)
@app.task(bind=True)
def debug_task(self):
print('Request: {0!r}'.format(self.request))
"""
Django settings for memopol project.
For more information on this file, see
https://docs.djangoproject.com/en/1.7/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.7/ref/settings/
"""
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
import json
import os
import django
# Normally you should not import ANYTHING from Django directly
# into your settings, but ImproperlyConfigured is an exception.
from django.core.exceptions import ImproperlyConfigured
from django.conf import settings
# BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
config_file = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'config.json')
with open(config_file) as f:
config = json.loads(f.read())
def get_param(setting, config=config, default=None):
"""Get the secret variable or return explicit exception."""
try:
return config[setting]
except KeyError:
if default:
return default
error_msg = "Set the {0} config variable".format(setting)
raise ImproperlyConfigured(error_msg)
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.7/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = get_param('secret_key')
DEBUG = get_param('debug')
TEMPLATE_DEBUG = DEBUG
ALLOWED_HOSTS = []
COMPOTISTA_SERVER = get_param('compotista_server')
TOUTATIS_SERVER = get_param('toutatis_server')
REDIS_DB = get_param('redis_db')
ORGANIZATION_NAME = get_param('organization')
# Application definition
INSTALLED_APPS = (
# 'django.contrib.admin',
# Instead of contrib.admin to use Django-Admin-Plus
'django.contrib.admin.apps.SimpleAdminConfig',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django.contrib.humanize',
# 3rd party app
'compressor',
'adminplus',
'constance',
'bootstrap3',
'datetimewidget',
# ---
'core',
'representatives',
'representatives_votes',
'legislature',
'votes',
'positions'
)
if DEBUG:
INSTALLED_APPS += (
'django_extensions',
)
if get_param('local'):
INSTALLED_APPS += (
'debug_toolbar',
)
MIDDLEWARE_CLASSES = (
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
)
ROOT_URLCONF = 'memopol.urls'
WSGI_APPLICATION = 'memopol.wsgi.application'
# Database
# https://docs.djangoproject.com/en/1.7/ref/settings/#databases
DATABASES = {
'default': {
'NAME': get_param('database_name'),
'USER': get_param('database_user'),
'PASSWORD': get_param('database_password'),
'HOST': get_param('database_host'),
'PORT': get_param('database_port'),
}
}
if get_param('database_server') == 'mysql':
DATABASES['default']['ENGINE'] = 'django.db.backends.mysql'
elif get_param('database_server') == 'postgresql':
DATABASES['default']['ENGINE'] = 'django.db.backends.postgresql_psycopg2'
# Internationalization
# https://docs.djangoproject.com/en/1.7/topics/i18n/
LANGUAGE_CODE = get_param('language_code', default='en-us')
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.7/howto/static-files/
STATIC_URL = '/static/'
# HAML Templates
# https://github.com/jessemiller/hamlpy
TEMPLATE_DIRS = (
'core/templates',
os.path.dirname(django.__file__)
)
TEMPLATE_LOADERS = (
'django.template.loaders.filesystem.Loader',
'django.template.loaders.app_directories.Loader',
'hamlpy.template.loaders.HamlPyFilesystemLoader',
'hamlpy.template.loaders.HamlPyAppDirectoriesLoader',
)
TEMPLATE_CONTEXT_PROCESSORS = settings.TEMPLATE_CONTEXT_PROCESSORS + (
'constance.context_processors.config',
)
"""
TEMPLATE_LOADERS = (
('django.template.loaders.cached.Loader', (
'hamlpy.template.loaders.HamlPyFilesystemLoader',
'hamlpy.template.loaders.HamlPyAppDirectoriesLoader',
)),
)
"""
# Static files finders
STATIC_URL = '/static/'
COMPRESS_ROOT = 'static/'
STATICFILES_FINDERS = (
'django.contrib.staticfiles.finders.FileSystemFinder',
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
# Compressor finder
'compressor.finders.CompressorFinder',
)
# Use compressor even in debug
COMPRESS_ENABLED = False
COMPRESS_PRECOMPILERS = (
# ('text/coffeescript', 'coffee --compile --stdio'),
('text/less', 'lessc {infile} {outfile}'),
('text/x-sass', 'sass {infile} {outfile}'),
('text/x-scss', 'sass --scss {infile} {outfile}'),
# ('text/stylus', 'stylus < {infile} > {outfile}'),
# ('text/foobar', 'path.to.MyPrecompilerFilter'),
)
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'verbose': {
'format': '%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s'
},
'simple': {
'format': '%(levelname)s[%(module)s]: %(message)s'
},
},
'handlers': {
'file': {
'level': 'DEBUG',
'class': 'logging.FileHandler',
'filename': '/tmp/compotista-debug.log',
},
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
'formatter': 'simple'
},
},
'loggers': {
'memopol': {
'handlers': ['console'],
'level': 'DEBUG'
},
'representatives': {
'handlers': ['console'],
'level': 'DEBUG'
},
'representatives_votes': {
'handlers': ['console'],
'level': 'DEBUG'
}
},
}
CONSTANCE_BACKEND = 'constance.backends.redisd.RedisBackend'
CONSTANCE_REDIS_CONNECTION = {
'host': 'localhost',
'port': 6379,
'db': 0,
}
CONSTANCE_CONFIG = {
'USE_COUNTRY': (True, 'Use country for representative'),
'MAIN_GROUP_KIND': ('group', 'Main group kind'),
'ORGANIZATION_NAME': ('La Quadrature du Net', 'Organization name'),
'POSITION_PUBLISHED': (False, 'Default position published status')
}
"""
Django settings for memopol project.
For more information on this file, see
https://docs.djangoproject.com/en/1.7/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.7/ref/settings/
"""
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
import os
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.7/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'zbzzs+8wkdnbo-l9x6+r38)$%h)!&22c^di$^6ap_+9oza#irr'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
TEMPLATE_DEBUG = True
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = (
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
# ---
'compressor',
'chronograph',
# ---
'core',
'representatives',
'memopol_representatives',
)
# App settings
REPRESENTATIVES_COMPOTISTA_SERVER = 'http://pi2.octopuce.fr:8081'
MIDDLEWARE_CLASSES = (
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
)
ROOT_URLCONF = 'memopol.urls'
WSGI_APPLICATION = 'memopol.wsgi.application'
# Database
# https://docs.djangoproject.com/en/1.7/ref/settings/#databases
DATABASES = {
'sqlite': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
},
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'memopol_dev',
'USER': 'dj',
'PASSWORD': "test",
'HOST': 'localhost',
'PORT': '',
}
}
# Internationalization
# https://docs.djangoproject.com/en/1.7/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.7/howto/static-files/
STATIC_URL = '/static/'
# HAML Templates
# https://github.com/jessemiller/hamlpy
TEMPLATE_DIRS = (
'core/templates',
)
TEMPLATE_LOADERS = (
'django.template.loaders.filesystem.Loader',
'django.template.loaders.app_directories.Loader',
'hamlpy.template.loaders.HamlPyFilesystemLoader',
'hamlpy.template.loaders.HamlPyAppDirectoriesLoader',
)
"""
TEMPLATE_LOADERS = (
('django.template.loaders.cached.Loader', (
'hamlpy.template.loaders.HamlPyFilesystemLoader',
'hamlpy.template.loaders.HamlPyAppDirectoriesLoader',
)),
)
"""
# Static files finders
STATIC_URL = '/static/'
COMPRESS_ROOT = 'static/'
STATICFILES_FINDERS = (
'django.contrib.staticfiles.finders.FileSystemFinder',
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
# other finders..
'compressor.finders.CompressorFinder',
)
COMPRESS_PRECOMPILERS = (
# ('text/coffeescript', 'coffee --compile --stdio'),
('text/less', 'lessc {infile} {outfile}'),
('text/x-sass', 'sass {infile} {outfile}'),
('text/x-scss', 'sass --scss {infile} {outfile}'),
# ('text/stylus', 'stylus < {infile} > {outfile}'),
# ('text/foobar', 'path.to.MyPrecompilerFilter'),
)
# coding: utf-8
# This file is part of memopol.
#
# memopol is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of
# the License, or any later version.
#
# memopol is distributed in the hope that it will
# be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU General Affero Public
# License along with django-representatives.
# If not, see <http://www.gnu.org/licenses/>.
#
# Copyright (C) 2015 Arnaud Fabre <af@laquadrature.net>
from django.conf.urls import patterns, include, url
from django.contrib import admin
from adminplus.sites import AdminSitePlus
import core.views
admin.site = AdminSitePlus()
admin.autodiscover()
urlpatterns = patterns('',
# Examples:
# url(r'^$', 'memopol.views.home', name='home'),
url(r'^$', core.views.HomeView.as_view(), name='index'),
url(r'^legislature/', include('legislature.urls', namespace='legislature')),
url(r'^votes/', include('votes.urls', namespace='votes')),
url(r'^positions/', include('positions.urls', namespace='positions')),
url(r'^admin/', include(admin.site.urls)),
)
import sys
def progress_bar(n, total):
progress = float(n) / total
sys.stdout.write("\r[{0:30s}] ({1}/{2}) {3}%".format('#' * int(progress * 30), n, total, int(progress * 100)))
{
"name": "memopol",
"version": "3.0.0",
"description": "git clone git@github.com:political-memory/django-representatives-votes.git git clone git@github.com:political-memory/django-representatives.git git clone git@github.com:political-memory/political_memory.git",
"main": "manage.py",
"dependencies": {
"gulp-livereload": "^3.8.0",
"gulp-gzip": "^1.1.0",
"gulp-less": "^3.0.3",
"gulp-minify-css": "^1.2.0",
"gulp-rename": "^1.2.2",
"gulp-watch": "^4.3.1"
},
"devDependencies": {},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git@git.laquadrature.net:memopol/memopol.git"
},
"author": "",
"license": "ISC"
}
# coding: utf-8
# This file is part of memopol.
#
# memopol is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of
# the License, or any later version.
#
# memopol is distributed in the hope that it will
# be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU General Affero Public
# License along with django-representatives.
# If not, see <http://www.gnu.org/licenses/>.
#
# Copyright (C) 2015 Arnaud Fabre <af@laquadrature.net>
from django import forms
from datetimewidget.widgets import DateWidget
from votes.models import MemopolDossier
from .models import Position
class PositionForm(forms.ModelForm):
class Meta:
model = Position
fields = ['dossier', 'datetime', 'text', 'link']
widgets = {
#Use localization and bootstrap 3
'datetime': DateWidget(
attrs={
'id':'yourdatetimeid'
},
usel10n = True,
bootstrap_version=3,
)
}
dossier = forms.ModelChoiceField(
queryset=MemopolDossier.objects.all(),
required=False
)
# coding: utf-8
# This file is part of memopol.
#
# memopol is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of
# the License, or any later version.
#
# memopol is distributed in the hope that it will
# be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU General Affero Public
# License along with django-representatives.
# If not, see <http://www.gnu.org/licenses/>.
#
# Copyright (C) 2015 Arnaud Fabre <af@laquadrature.net>
from django.db import models
from django.template.defaultfilters import truncatewords
from constance import config
from legislature.models import MemopolRepresentative
from votes.models import MemopolDossier
class PositionManager(models.Manager):
"""A simple model manager for querying published Positions"""
# https://docs.djangoproject.com/en/1.8/topics/db/managers/#using-managers-for-related-object-access
use_for_related_fields = True
def published(self, **kwargs):
return self.filter(published=True, **kwargs)
class Position(models.Model):
representative = models.ForeignKey(MemopolRepresentative, related_name='positions')
dossier = models.ForeignKey(MemopolDossier, null=True, blank=True)
datetime = models.DateField()
text = models.TextField()
link = models.URLField()
published = models.BooleanField(default=False)
# Adds our custom manager
objects = PositionManager()
def save(self, *args, **kwargs):
""" Set published to default value and save the model"""
self.published = config.POSITION_PUBLISHED
super(Position, self).save(*args, **kwargs)
@property
def short_text(self):
return truncatewords(self.text, 5)
def publish(self):
self.published = True
def unpublish(self):
self.published = False
- extends 'base.html'
- block content
- extends 'base.html'
- load humanize
- block content
- include 'legislature/blocks/representative_header.html' with representative=object.representative
.quote
%p.quote-header
The {{object.datetime|naturalday:"d/m/Y"}}, {{object.representative.full_name}} declared :
.long-quote
= object.text|linebreaks
%p
Source :
%a{:href => '{{object.link}}'}
= object.link
Test
from django.test import TestCase
# Create your tests here.
# coding: utf-8
# This file is part of memopol.
#
# memopol is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of
# the License, or any later version.
#
# memopol is distributed in the hope that it will
# be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU General Affero Public
# License along with django-representatives.
# If not, see <http://www.gnu.org/licenses/>.
#
# Copyright (C) 2015 Arnaud Fabre <af@laquadrature.net>
from django.conf.urls import url
from views import PositionCreate, PositionDetail
urlpatterns = [
# Create a Position
url(
r'^create',
PositionCreate.as_view(),
name='position-create'
),
url(
r'^(?P<pk>\d+)/$',
PositionDetail.as_view(),
name='position-detail'
)
]
# coding: utf-8
# This file is part of memopol.
#
# memopol is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of
# the License, or any later version.
#
# memopol is distributed in the hope that it will
# be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU General Affero Public
# License along with django-representatives.
# If not, see <http://www.gnu.org/licenses/>.
#
# Copyright (C) 2015 Arnaud Fabre <af@laquadrature.net>
from django.views.generic import CreateView
from django.views.generic.detail import DetailView
from django.core.urlresolvers import reverse
from .models import Position
from .forms import PositionForm
class PositionCreate(CreateView):
"""Create a position"""
model = Position
fields = PositionForm.Meta.fields + ['representative']
def get_success_url(self):
return reverse('legislature:representative-detail',
kwargs={'name': self.object.representative.slug})
class PositionDetail(DetailView):
"""Display a position"""
model = Position
queryset = Position.objects.filter(published=True)