Skip to content
Snippets Groups Projects
Commit f93be5bd authored by florimondmanca's avatar florimondmanca
Browse files

initial commit - copy from oser-backend and remove everything not related to showcase site

parents
No related branches found
No related tags found
No related merge requests found
Showing with 462 additions and 0 deletions
# virtualenvs
env/
venv/
virtualenv/
# build
*.pyc
__pycache__/
# Logs
*.log
# IDEA
.idea
.vscode
# databases
*.db
*.sqlite3
*.rdb
# private
# .env
# media and collected static files
project/media/
project/static/
# Supervisor
supervisord.pid
language: python
# Cache dependencies between builds
cache: pip
python:
- '3.6'
services:
- postgresql
- redis-server
install:
- pip install -r requirements.txt
# Supervisor < 4 does not support python 3 but Supervisor 4 is not
# released to PyPI yet. => Install from Github
- pip install git+https://github.com/Supervisor/supervisor.git
before_script:
# Start Celery using the supervisor config
- supervisord
# Create local PostgreSQL database
# NOTE: the database name (here 'oser_backend_db') must match the name
# in one of these DATABASE_URL setting:
# - the one set up in TravisCI environment variables
# - the one set up in settings/default.py
- psql -c 'create database oser_backend_db;' -U postgres
# Go to the project root directory
- cd oser_backend
# Apply database migrations
- python manage.py migrate
script:
# Run tests
- python manage.py test
before_deploy:
# Return the repository root
- cd .. && ls
deploy:
# Deploy to Heroku once the tests have passed
# See TravisCI docs: https://docs.travis-ci.com/user/deployment/heroku/
provider: heroku
app:
# direct each branch to the corresponding app
master: oser-backend
staging: oser-backend-staging
run:
# automatically run new migrations
- 'python oser_backend/manage.py migrate'
api_key:
# Encrypted API key obtained from the following command
# (requires TravisCI and Heroku CLI installed)
# $ travis encrypt $(heroku auth:token) --add deploy.api_key
secure: tk6Pfrftlma+m6TYwl3DODf4rrtoPbvL5C94rBWEyjE3ttyitFIMqWAhG/lVR83ZmCd+sGvm250fqKes2+ZINYW92csvu9vngG4018qzDJ0agA2wOsNkn+mMih96hk+uWpRHWZ90BDG/wWcWnquSzS2fNNmdJVS5lEH4lPQBrgN0dTlHROHnFn5eJK7BR/22EOfF2wmREdMohn7QDBalju+C5ywGKNVYJ9Lhychlp/LbemrHViIXheCO3dS0Lu+AsQaH0Gh+793tmHWqRJhY4EP0IKi6xguH9/b80hkgAH8zZYo8HOXCGBUJnTNWJsf5H4Dvcoeny0p6ak/oyudwO/ZEQB0bs5MeAa5yCunEb6nCnpmPy+spvVjK3ZSGLhfetYHn44tApzFNnqOJPnHSFHy0Tbi/RDFpH6998iUWx7MbXsjsxLnj1C/c53l5xg9YxbZKp8YBNlmwMKdBaEnZEiHyVBhJG05JVnacMUAajtOisObG2yKBjcgUxNuTRIFlSj8UKKlF+wnjrRQLGHK32ISkE+g4NAePtqU5W4hjKqpMvv9uNEopkGb9XNo+9PWN168s7trKWcLIaqNykAVS/0LUYomuV2tMdIcP7biYO84r1YRmFFblTIb19vFsQNagRRZ27gFnjozPufVmDF8tp3buEeEkRTDZZIcJfoGoJFM=
This diff is collapsed.
web: sh -c 'cd project && exec gunicorn project.wsgi:application --bind 0.0.0.0:$PORT --workers 1'
# Toggle next line to start Celery in a worker process
worker: sh -c 'cd project && exec celery -A project worker --beat -l info'
README.md 0 → 100644
# Site vitrine d'OSER - Backend
<p align="center"><img width=40% src="media/logo.png"></p>
<!-- Badges issus de Shields.io.
Les badges sont générés à partir de l'URL, qui ressemble à ceci :
https://img.shields.io/badge/<label>-<status>-couleur>.svg
Plus d'informations sur leur site : http://shields.io
-->
[![Python](https://img.shields.io/badge/python-3.6-blue.svg)](https://docs.python.org/3/)
[![Django](https://img.shields.io/badge/django-2.0-blue.svg)](https://www.djangoproject.com)
Bienvenue ! Ce dépôt est le lieu de développement du backend du site vitrine de l'association OSER.
Ce backend gère les resources telles que les articles, témoignages et autres données liées au site vitrine. Les resources sont exposées via une API.
Voir aussi :
- [Dépôt du site membres](https://github.com/oser-cs/oser-backend/).
## Table des matières
- [Installation](#installation)
- [Dépendances](#dépendances)
- [À propos d'OSER](#À-propos-doser)
## Installation
Cette section vous explique comment installer le site sur votre ordinateur pour le faire tourner en mode développement.
### Logiciels
- [Python 3.5+](https://www.python.org/downloads/)
- [PostgreSQL](https://www.postgresql.org/download/)
Après avoir installé PostgreSQL, **démarrez le serveur** en ouvrant pgAdmin, l'interface graphique qui sera installée en même temps que Postgres.
Il vous faut aussi créer la base de données appelée `oser_showcase_backend_db`.
Pour cela, l'utilitaire `psql` devrait s'être installé avec PostgreSQL, donc
exécutez la commande suivante :
```sh
$ psql -c "create database oser_showcase_backend_db"
```
- Optionnel : [Redis](https://redis.io) et [supervisord](http://supervisord.org) (utilisés par le gestionnaire de tâches [Celery](http://www.celeryproject.org))
Supervisord permet de lancer Redis (un système de *messaging*) et Celery en une seule commande, à exécuter à la racine du dépôt :
```sh
$ supervisord
```
Supervisord ne supporte toujours pas officiellement Python 3, mais c'est le cas pour la dernière version de développement. Installez-donc celle-ci :
```sh
$ pip install git+https://github.com/Supervisor/supervisor.git
```
> Il n'est pas obligatoire d'installer Redis, supervisord et Celery en développement. Sachez simplement alors que le test d'intégration associé échouera lorsque vous exécuterez les tests.
### Installation du projet
- Créez un environnement virtuel (appelé `env`) puis activez-le :
```bash
$ python -m venv env
$ source env/bin/activate
```
- Installez les dépendances :
```bash
$ pip install -r requirements.txt
```
- Configurez la base de données en exécutant les migrations (rappelez-vous : *le serveur PostgreSQL doit être actif*) :
```bash
$ cd project
$ python manage.py migrate
```
Il ne vous reste plus qu'à lancer le serveur de développement :
```bash
$ python manage.py runserver
```
Celui-ci sera accessible à l'adresse http://localhost:8000.
### Accéder à l'administration
L'interface d'administration du site permet d'effectuer des opérations d'administration (gestion des permissions utilisateur, modifications de données…). Elle permet en particulier aux gestionnaires du site vitrine d'apporter des modifications à son contenu ainsi que d'éditer des articles.
Lorsque vous accédez au site (par exemple à http://localhost:8000), vous êtes redirigés vers la page d'authentification. Authentifiez-vous avec un compte autorisé (compte administrateur ou autre compte avec le statut `staff`).
En développement, si vous venez d'installer le site, il n'y a pas encore d'utilisateurs dans la BDD. Il vous faut donc créer un compte administrateur. Pour cela, exécutez la commande `initadmin` :
```bash
$ python manage.py initadmin
```
Les identifiants par défaut sont indiqués dans le fichier `settings/common.py`. En production, pensez à mettre à jour le mot de passe de ce compte !
> Pour des raisons de sécurité, cette commande produira une erreur si des utilisateurs existent déjà dans la base de données. Vous ne pouvez donc l'exécuter que sur une BDD vide.
### Documentation de l'API
En développement, vous pouvez accéder à la documentation de l'API à l'adresse http://localhost:8000/api/docs.
Vous pouvez aussi librement parcourir l'API à l'adresse http://localhost:8000/api.
Vous pouvez également accéder à la documentation de [l'API en production](http://oser-showcase-backend.herokuapp.com/api/docs).
![API Docs](media/api-docs.png)
## Dépendances
### Django
[Django](https://www.djangoproject.com) est un framework de développement web pour Python. Le site d'OSER utilise Django en version 2.0.
### Django REST Framework
Le [Django REST Framework](http://www.django-rest-framework.org) (DRF) permet d'écrire facilement des API REST avec Django.
Le site d'OSER utilise le DRF en version 3.8+.
## À propos d'OSER
OSER, ou Ouverture Sociale pour la Réussite, est une association étudiante de CentraleSupélec œuvrant dans le cadre des Cordées de la Réussite. Elle accompagne des jeunes issus de tous milieux sociaux et leur propose à cet effet un programme de tutorat, des sorties culturels, des séjours thématiques ou encore des stages de découverte.
media/api-docs.png

185 KiB

media/logo.png

27.3 KiB

from django.apps import AppConfig
class ApiConfig(AppConfig):
name = 'api'
"""API routers."""
from rest_framework import routers
from core import views as core_views
from showcase_site import views as showcase_site_views
app_name = 'api'
# Register API routes here
router = routers.DefaultRouter(trailing_slash=True)
# Showcase site views
router.register('articles', showcase_site_views.ArticleViewSet)
router.register('categories', showcase_site_views.CategoryViewSet)
router.register('testimonies', showcase_site_views.TestimonyViewSet)
router.register('keyfigures', showcase_site_views.KeyFigureViewSet)
router.register('partners', showcase_site_views.PartnerViewSet)
router.register('actions', showcase_site_views.ActionViewSet)
# Core views
router.register('documents', core_views.DocumentViewSet)
urlpatterns = router.urls
"""Define AWS storage backends for static and media files.
We do this to make sure static and media files are stored in different
directories in the S3 bucket (defined by the 'location' below).
"""
from storages.backends.s3boto3 import S3Boto3Storage
# uncomment and update aws/conf.py to use for storing static files on AWS
# def StaticBackend():
# """Static storage backend."""
# return S3Boto3Storage(location='static')
def MediaBackend():
"""Media storage backend."""
return S3Boto3Storage(location='media')
"""Amazon S3 storage configuration.
See:
- http://django-storages.readthedocs.io/en/latest/backends/amazon-S3.html
- https://www.codingforentrepreneurs.com/blog/s3-static-media-files-for-django/
"""
import os
# Use S3 backends
DEFAULT_FILE_STORAGE = 'aws.backends.MediaBackend'
# Uncomment STATICFILES_STORAGE to store static files on AWS
# Beware that Heroku automatically calls 'manage.py collectstatic' for
# each deployment, and this backend does not support checking for pre-existing
# static files on AWS : all the static files will be uploaded on each
# deployment.
# It can be OK to set DISABLE_COLLECTSTATIC on Heroku, but then
# you'd have to run collectstatic manually on Heroku when necessary.
# Since static files on the backend should not change a lot, it seems OK
# to simply use the default file storage for static files.
# STATICFILES_STORAGE = 'aws.backends.StaticBackend'
# Credentials
AWS_ACCESS_KEY_ID = os.environ.get('AWS_ACCESS_KEY_ID')
AWS_SECRET_ACCESS_KEY = os.environ.get('AWS_SECRET_ACCESS_KEY')
# Name of the storage bucket
AWS_STORAGE_BUCKET_NAME = os.environ.get('AWS_STORAGE_BUCKET_NAME')
# Region of the storage bucket (e.g. eu-west-1)
AWS_S3_REGION_NAME = os.environ.get('AWS_S3_REGION_NAME')
# Do not overwrite files with the same name
AWS_S3_FILE_OVERWRITE = False
# Use the new signature version
AWS_S3_SIGNATURE_VERSION = 's3v4'
# Misc
AWS_S3_OBJECT_PARAMETERS = {
'CacheControl': 'max-age=86400',
}
AWS_S3_CUSTOM_DOMAIN = (
'{bucket}.s3.amazonaws.com'
.format(bucket=AWS_STORAGE_BUCKET_NAME))
# Redefine media URL to upload/retrieve to/from S3
MEDIA_URL = 'https://' + AWS_S3_CUSTOM_DOMAIN + 'media/'
# Direct the MEDIA_ROOT to the media/ directory inside the bucket
MEDIA_ROOT = 'media'
"""Core admin panel configuration."""
from django.contrib import admin
from .models import Document, Address
# Register your models here.
@admin.register(Document)
class DocumentAdmin(admin.ModelAdmin):
"""Admin panel for documents."""
list_display = ('title', 'slug',)
readonly_fields = ('slug',)
# reorganize fields
fields = ('title', 'slug', 'content',)
@admin.register(Address)
class AddressAdmin(admin.ModelAdmin):
"""Admin panel for addresses."""
list_display = ('id', '__str__',)
search_fields = ('line1', 'line2', 'post_code', 'city',)
class AutocompleteAddressMixin:
"""Enable autocompletion on the address field of a model.
Class Attributes
----------------
address_field_name : str, optional
The name of the address field on the model. Default is 'address'.
"""
address_field_name = 'address'
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
initial = getattr(self, 'autocomplete_fields', ())
if self.address_field_name not in initial:
self.autocomplete_fields = initial + (self.address_field_name,)
from django.apps import AppConfig
class CoreConfig(AppConfig):
name = 'core'
verbose_name = 'Général'
"""Core factories."""
import factory
import factory.django
from . import models
class DocumentFactory(factory.DjangoModelFactory):
"""Document object factory."""
class Meta: # noqa
model = models.Document
title = factory.Faker('sentence', locale='fr')
content = factory.Faker('text', max_nb_chars=1000, locale='fr')
class AddressFactory(factory.DjangoModelFactory):
"""Address object factory."""
class Meta: # noqa
model = models.Address
line1 = factory.Faker('street_address', locale='fr')
# line2: None (default)
post_code = factory.Faker('postcode', locale='fr')
city = factory.Faker('city', locale='fr')
# country: None (default)
"""Various file utilities."""
import os
import fnmatch
def locate(pattern, root=os.curdir):
"""Locate all files matching pattern in and below given root directory."""
for path, dirs, files in os.walk(os.path.abspath(root)):
for filename in fnmatch.filter(files, pattern):
yield os.path.join(path, filename)
def find_file(pattern, root=os.curdir):
"""Return first occurence of matching file in and below root.
If no occurence file, raises a FileNotFoundError.
"""
for path in locate(pattern, root=root):
return path
raise FileNotFoundError(pattern)
def walk(storage, top='/', topdown=True, onerror=None):
"""Implement os.walk using a Django storage.
Refer to the documentation of os.walk().
Inspired by: https://gist.github.com/btimby/2175107
Parameters
----------
storage : django.Storage
top : str, optional
Same role as in os.walk().
The path at which the walk should begin. Root directory by default.
topdown : bool, optional
Same role and default value as in os.walk().
onerror : function, optional
Same role and default value as in os.walk().
"""
try:
dirs, nondirs = storage.listdir(top)
except (os.error, Exception) as err:
if onerror is not None:
onerror(err)
return
if topdown:
yield top, dirs, nondirs
for name in dirs:
new_path = os.path.join(top, name)
# recursively list subdirectories
for top_, dirs_, nondirs_ in walk(storage, top=new_path):
yield top_, dirs_, nondirs_
if not topdown:
yield top, dirs, nondirs
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment