Skip to content

Commit

Permalink
✨(funcampus) add a new funcampus site for the future fun-campus.fr
Browse files Browse the repository at this point in the history
I copy/pasted the funcorporate site and substituted "corporate" by
"campus".
  • Loading branch information
sampaccoud committed Jul 23, 2020
1 parent 185f9de commit 45e23c2
Show file tree
Hide file tree
Showing 52 changed files with 10,616 additions and 0 deletions.
62 changes: 62 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,68 @@ workflows:
tags:
only: /.*/
name: no-change-demo
funcampus:
jobs:
- check-changelog:
filters:
branches:
ignore: master
name: check-changelog-funcampus
site: funcampus
- lint-changelog:
filters:
branches:
ignore: master
tags:
only: /funcampus-.*/
name: lint-changelog--funcampus
site: funcampus
- build-front-production:
filters:
tags:
only: /funcampus-.*/
name: build-front-production-funcampus
site: funcampus
- lint-front:
filters:
tags:
only: /funcampus-.*/
name: lint-front-funcampus
requires:
- build-front-production-funcampus
site: funcampus
- build-back:
filters:
tags:
only: /funcampus-.*/
name: build-back-funcampus
site: funcampus
- lint-back:
filters:
tags:
only: /funcampus-.*/
name: lint-back-funcampus
requires:
- build-back-funcampus
site: funcampus
- test-back:
filters:
tags:
only: /funcampus-.*/
name: test-back-funcampus
requires:
- build-back-funcampus
site: funcampus
- hub:
filters:
tags:
only: /^funcampus-.*/
image_name: funcampus
name: hub-funcampus
requires:
- lint-front-funcampus
- lint-back-funcampus
site: funcampus
funcorporate:
jobs:
- no-change:
Expand Down
16 changes: 16 additions & 0 deletions sites/funcampus/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic
Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

## [0.1.0] - 2020-07-23

First funcampus image

[unreleased]: https://github.com/openfun/richie-site-factory/compare/funcampus-0.1.0...HEAD
[funcampus-0.1.0]: https://github.com/openfun/richie-site-factory/compare/ 185f9deff5c4dd79e21f4f42c2acd1d17c73c293...funcampus-0.1.0
7 changes: 7 additions & 0 deletions sites/funcampus/aws/config.tfvars
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
site = "funcampus"

app_domain = {
production = "new.fun-campus.fr"
preprod = "preprod.funedu.oc.openfun.fr"
staging = "staging.funedu.oc.openfun.fr"
}
16 changes: 16 additions & 0 deletions sites/funcampus/requirements/base.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
boto3==1.9.96
Django<3
django-configurations==2.2
# Superior versions of django-storages are not compatible with
# ManifestStaticFilesStorage
django-storages==1.9.1
dockerflow==2019.10.0
gunicorn==20.0.4
psycopg2-binary==2.8.5
richie==2.0.0-beta.8
sentry-sdk==0.14.3

# Google sheet importer
gspread==3.1.0
markdown==3.1.1
oauth2client==4.1.3
11 changes: 11 additions & 0 deletions sites/funcampus/requirements/dev.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
bandit==1.6.2
black==19.10b0
Faker==1.0.4
factory-boy==2.12.0
flake8==3.7.9
isort==4.3.21
pylint==2.5.2
pylint-django==2.0.15
pytest==5.4.2
pytest-cov==2.8.1
pytest-django==3.9.0
Empty file.
Empty file.
41 changes: 41 additions & 0 deletions sites/funcampus/src/backend/base/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
"""Admin overrides for fun-campus."""
from django.contrib import admin, auth
from django.contrib.auth.admin import UserAdmin
from django.http import JsonResponse
from django.utils.translation import ugettext_lazy as _
from django.views.decorators.csrf import csrf_exempt

from filer.admin import clipboardadmin
from filer.admin.clipboardadmin import ajax_upload as filer_ajax_upload
from filer.models.virtualitems import FolderRoot


class CustomUserAdmin(UserAdmin):
"""
Override the user admin to customize its behavior.
The original user admin is unregistered below in order to make place for this custom admin.
"""

def get_readonly_fields(self, request, obj=None):
"""Make the superuser field readonly for staff users that are not superuser themselves."""
extra_readonly_fields = (
("is_superuser",) if not request.user.is_superuser else ()
)
return self.readonly_fields + extra_readonly_fields


@csrf_exempt
def ajax_upload(request, folder_id=None):
"""Disallow unsorted uploads."""
if folder_id is None:
return JsonResponse({"error": _("Unsorted uploads are not allowed.")})

return filer_ajax_upload(request, folder_id=folder_id)


clipboardadmin.ajax_upload = ajax_upload
FolderRoot.virtual_folders = lambda o: []

user_model = auth.get_user_model()
admin.site.unregister(user_model)
admin.site.register(user_model, CustomUserAdmin)
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<browserconfig>
<msapplication>
<tile>
<square150x150logo src="/static/richie/favicon/mstile-150x150.png"/>
<TileColor>#ffffff</TileColor>
</tile>
</msapplication>
</browserconfig>
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"name": "",
"short_name": "",
"icons": [
{
"src": "/static/richie/favicon/android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/static/richie/favicon/android-chrome-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
],
"theme_color": "#ffffff",
"background_color": "#ffffff",
"display": "standalone"
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
61 changes: 61 additions & 0 deletions sites/funcampus/src/backend/base/storage.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
"""Customizing Django storage backends to enable blue/green deployments."""
import re
from collections import OrderedDict

from django.conf import settings
from django.contrib.staticfiles.storage import ManifestStaticFilesStorage

from storages.backends.s3boto3 import S3Boto3Storage

STATIC_POSTPROCESS_IGNORE_REGEX = re.compile(r"^richie\/js\/[0-9]*\..*\.index\.js$")


class CDNManifestStaticFilesStorage(ManifestStaticFilesStorage):
"""
Manifest static files storage backend that can be placed behing a CDN
and ignores files that are already versioned by webpack.
"""

def post_process(self, paths, dry_run=False, **options):
"""
Remove paths from file to post process.
Some js static files generated by webpack already have a unique name per build
and may be referenced from within the js applications. We therefore don't want
to hash their name and include them in the manifest file.
We use a regex configurable via settings to decide which files to ignore.
Parameters
----------
paths : OrderedDict
List of files to post process
dry_run: boolean
run process but nothing is apply if True
options: kwargs
See HashedFilesMixin.post_process
"""
filtered_paths = OrderedDict()
for path in paths:
if not STATIC_POSTPROCESS_IGNORE_REGEX.match(path):
filtered_paths[path] = paths[path]

yield from super().post_process(filtered_paths, dry_run=dry_run, **options)

def url(self, name, force=False):
"""
Prepend static files path by the CDN base url when configured in settings.
"""
url = super().url(name, force=force)

cdn_domain = getattr(settings, "CDN_DOMAIN", None)
if cdn_domain:
url = f"//{cdn_domain:s}{url:s}"

return url


class MediaStorage(S3Boto3Storage):
"""A S3Boto3Storage backend to serve media files via CloudFront."""

bucket_name = getattr(settings, "AWS_MEDIA_BUCKET_NAME", None)
custom_domain = getattr(settings, "CDN_DOMAIN", None)
file_overwrite = False
location = settings.MEDIA_URL
Empty file.
50 changes: 50 additions & 0 deletions sites/funcampus/src/backend/base/tests/test_settings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
"""Test fun-campus configuration."""
from unittest import mock

from django.conf import settings
from django.test import TestCase, override_settings

from rest_framework.response import Response
from rest_framework.settings import DEFAULTS, api_settings
from richie.apps.search.viewsets.courses import CoursesViewSet


class ConfigurationTestCase(TestCase):
"""Validate that our configuration works as expected."""

@mock.patch.object(CoursesViewSet, "list", spec=True, return_value=Response({}))
def test_configuration_restframework_htaccess(self, _mock_list):
"""The search API endpoint should work behind an htaccess."""
# First, check that API calls were broken with the default DRF configuration
# What was happening is that DRF defines Basic Authentication as a fallback by default
# and our query has a basic auth header with the username and password of the htaccess
# defined in nginx. Django was trying to authenticate a user with these credentials,
# which of course failed.
with override_settings(
REST_FRAMEWORK={
**settings.REST_FRAMEWORK,
"DEFAULT_AUTHENTICATION_CLASSES": DEFAULTS[
"DEFAULT_AUTHENTICATION_CLASSES"
],
}
):
authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES

# The authentication classes are loaded before settings are overriden so we need
# to mock them on the APIView
with mock.patch(
"rest_framework.views.APIView.authentication_classes",
new_callable=mock.PropertyMock,
return_value=authentication_classes,
):
response = self.client.get(
"/api/v1.0/courses/",
HTTP_AUTHORIZATION="Basic dXNlcm5hbWU6cGFzc3dvcmQ=",
)
self.assertEqual(response.status_code, 403)

# Check that the project configuration solves it
response = self.client.get(
"/api/v1.0/courses/", HTTP_AUTHORIZATION="Basic dXNlcm5hbWU6cGFzc3dvcmQ="
)
self.assertEqual(response.status_code, 200)
1 change: 1 addition & 0 deletions sites/funcampus/src/backend/funcampus/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
__version__ = "0.1.0"
Loading

0 comments on commit 45e23c2

Please sign in to comment.