Browse Source

Initial commit

pull/16/head
Matīss Treinis 4 years ago
commit
8dd9eecfa2
No known key found for this signature in database GPG Key ID: 3781D64D73F1907F
  1. 37
      .editorconfig
  2. 4
      .gitignore
  3. 3
      .venv/.gitignore
  4. 31
      Dockerfile
  5. 25
      Dockerfile-frontend
  6. 19
      LICENSE
  7. 64
      Makefile
  8. 13
      Pipfile
  9. 63
      Pipfile.lock
  10. 37
      README.md
  11. 0
      almalinux/__init__.py
  12. 9
      almalinux/admin.py
  13. 5
      almalinux/apps.py
  14. 16
      almalinux/asgi.py
  15. 158
      almalinux/settings.py
  16. 36
      almalinux/urls.py
  17. 16
      almalinux/wsgi.py
  18. 3
      commons/__init__.py
  19. 5
      commons/apps.py
  20. 48
      commons/encore.py
  21. 0
      commons/templatetags/__init__.py
  22. 34
      commons/templatetags/encore.py
  23. 23
      commons/uploads.py
  24. 50
      docker-compose.yml
  25. 1
      frontend/.gitignore
  26. 41
      frontend/README.md
  27. 29
      frontend/package.json
  28. 5
      frontend/postcss.config.js
  29. 3
      frontend/src/common/js/main.js
  30. 2
      frontend/src/common/scss/main.scss
  31. 18
      frontend/src/django.mock.js
  32. 0
      frontend/src/modules/.gitignore
  33. 47
      frontend/webpack.config.js
  34. 6300
      frontend/yarn.lock
  35. 22
      locale/es/LC_MESSAGES/django.po
  36. 22
      locale/es/LC_MESSAGES/djangojs.po
  37. 20
      locale/ru/LC_MESSAGES/django.po
  38. 20
      locale/ru/LC_MESSAGES/djangojs.po
  39. 22
      manage.py
  40. 2
      media/.gitignore
  41. 0
      static/.gitignore
  42. 0
      www/__init__.py
  43. 15
      www/admin.py
  44. 5
      www/apps.py
  45. 0
      www/migrations/__init__.py
  46. 1
      www/models.py
  47. 6
      www/templates/index.html
  48. 20
      www/templates/layouts/base.html
  49. 1
      www/tests.py
  50. 7
      www/urls.py
  51. 6
      www/views.py

37
.editorconfig

@ -0,0 +1,37 @@
root = true
[*]
end_of_line = lf
insert_final_newline = true
charset = utf-8
[*.py]
indent_style = space
indent_size = 4
ij_continuation_indent_size = 4
[*.js]
indent_style = space
indent_size = 4
ij_continuation_indent_size = 4
[*.scss]
indent_style = space
indent_size = 2
[*.html]
indent_style = space
indent_size = 4
ij_continuation_indent_size = 4
[{*.yml, *.yaml}]
indent_style = space
indent_size = 2
[*.svg]
indent_style = space
indent_size = 2
[{package.json, tsconfig.json}]
indent_style = space
indent_size = 4

4
.gitignore

@ -0,0 +1,4 @@
node_modules
db.sqlite3
static/build
*.mo

3
.venv/.gitignore

@ -0,0 +1,3 @@
# Keep .venv around in the project source to avoid pipenv creating new user-local venvs
*
!.gitignore

31
Dockerfile

@ -0,0 +1,31 @@
# Docker image for local development environment.
# You should NOT publish this image, it is intended for local use only.
FROM almalinux/almalinux:8
ARG LOCAL_UID
ARG LOCAL_GID
RUN groupadd -g ${LOCAL_GID} web && \
useradd -ms /bin/bash web -g ${LOCAL_GID} -u ${LOCAL_UID}
RUN dnf -y install \
gcc \
make \
gettext \
python38 \
python38-devel \
mariadb-devel
RUN pip3 install pipenv
# Work around IDEA remote interpreter not able to work with remote virtualenvs
RUN touch /root/.bashrc \
&& echo 'if [[ -f "/app/.venv/bin/activate" ]]; then source /app/.venv/bin/activate; fi' >> /root/.bashrc
RUN touch /home/web/.bashrc \
&& echo 'if [[ -f "/app/.venv/bin/activate" ]]; then source /app/.venv/bin/activate; fi' >> /home/web/.bashrc
WORKDIR /app
CMD make runserver

25
Dockerfile-frontend

@ -0,0 +1,25 @@
# Docker image for local development environment.
# You should NOT publish this image, it is intended for local use only.
FROM almalinux/almalinux:8
ARG LOCAL_UID
ARG LOCAL_GID
RUN groupadd -g ${LOCAL_GID} web && \
useradd -ms /bin/bash web -g ${LOCAL_GID} -u ${LOCAL_UID}
RUN dnf -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm && \
dnf -y install yum-utils && \
curl -fsSL https://rpm.nodesource.com/setup_15.x | bash - && \
curl -sL https://dl.yarnpkg.com/rpm/yarn.repo | tee /etc/yum.repos.d/yarn.repo
RUN dnf -y install \
make \
gcc-c++ \
nodejs \
yarn
WORKDIR /app
CMD make frontend-runserver

19
LICENSE

@ -0,0 +1,19 @@
Copyright (c) 2021 AlmaLinux OS Foundation
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

64
Makefile

@ -0,0 +1,64 @@
ROOT_DIR := $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))
CURRENT_UID := $(shell id -u)
CURRENT_GID := $(shell id -g)
.PHONY: default
default: dev ;
dev: #: Start development environment
LOCAL_UID=${CURRENT_UID} LOCAL_GID=${CURRENT_GID} docker-compose up --abort-on-container-exit
build-dev: #: Build development Docker images
LOCAL_UID=${CURRENT_UID} LOCAL_GID=${CURRENT_GID} docker-compose build web
LOCAL_UID=${CURRENT_UID} LOCAL_GID=${CURRENT_GID} docker-compose build frontend
clean-dev: #: Clean development environment, remove docker images and data
LOCAL_UID=${CURRENT_UID} LOCAL_GID=${CURRENT_GID} docker-compose down --rmi local -v
web-shell: #: Enter backend shell within docker, as a regular user, new service instance
LOCAL_UID=${CURRENT_UID} LOCAL_GID=${CURRENT_GID} docker-compose run -u ${CURRENT_UID} web /bin/bash
web-root-shell: #: Enter backend shell within docker, as root, new service instance
LOCAL_UID=${CURRENT_UID} LOCAL_GID=${CURRENT_GID} docker-compose run web /bin/bash
web-attach: #: Attach to backend shell within docker, as a regular user, running instance
docker exec -ti -u ${CURRENT_UID} web /bin/bash
web-root-attach: #: Attach to backend shell within docker, as root, running instance
docker exec -ti web /bin/bash
frontend-shell: #: Enter frontend shell within docker, as a regular user, new service instance
LOCAL_UID=${CURRENT_UID} LOCAL_GID=${CURRENT_GID} docker-compose run -u ${CURRENT_UID} frontend /bin/bash
frontend-root-shell: #: Enter frontend shell within docker, as root, new service instance
LOCAL_UID=${CURRENT_UID} LOCAL_GID=${CURRENT_GID} docker-compose run frontend /bin/bash
frontend-attach: #: Attach to frontend shell within docker, as a regular user, running instance
docker exec -ti -u ${CURRENT_UID} frontend /bin/bash
frontend-root-attach: #: Attach to frontend shell within docker, as root, running instance
docker exec -ti frontend /bin/bash
dist: #: Assemble a distributable archive
@echo 'TODO'
deploy: #: Deploy project
@echo 'TODO'
runserver: # INTERNAL - start internal development server. This is supposed to be run inside Docker.
su - web -c 'cd /app && pipenv install'
su - web -c 'cd /app && pipenv run python3 manage.py migrate'
su - web -c 'cd /app && pipenv run python3 manage.py runserver 0.0.0.0:8080'
frontend-runserver: # INTERNAL - start internal frontend development server. This is supposed to be run inside Docker.
su - web -c 'yarn --cwd=/app/frontend/ install'
su - web -c 'yarn --cwd=/app/frontend/ dev-server --host 0.0.0.0 --public http://localhost:8090 --port 8090'
help: #: Show this help
@fgrep -h "#:" $(MAKEFILE_LIST) | fgrep -v fgrep | sed -e 's/\\$$//' | sed -e 's/#://'
all: dev
%:
@echo 'Invalid command'
@make help

13
Pipfile

@ -0,0 +1,13 @@
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"
[packages]
Django = "~=3.2"
mysqlclient = "~=2.0.3"
[dev-packages]
[requires]
python_version = "3.8"

63
Pipfile.lock

@ -0,0 +1,63 @@
{
"_meta": {
"hash": {
"sha256": "a6e76f6ff312340357f1c08cde19e71b1c31343b30fe186fa5adad14cd1a0f66"
},
"pipfile-spec": 6,
"requires": {
"python_version": "3.8"
},
"sources": [
{
"name": "pypi",
"url": "https://pypi.org/simple",
"verify_ssl": true
}
]
},
"default": {
"asgiref": {
"hashes": [
"sha256:92906c611ce6c967347bbfea733f13d6313901d54dcca88195eaeb52b2a8e8ee",
"sha256:d1216dfbdfb63826470995d31caed36225dcaf34f182e0fa257a4dd9e86f1b78"
],
"markers": "python_version >= '3.6'",
"version": "==3.3.4"
},
"django": {
"hashes": [
"sha256:95c13c750f1f214abadec92b82c2768a5e795e6c2ebd0b4126f895ce9efffcdd",
"sha256:e2f73790c60188d3f94f08f644de249d956b3789161e7604509d128a13fb2fcc"
],
"index": "pypi",
"version": "==3.2.1"
},
"mysqlclient": {
"hashes": [
"sha256:0ac0dd759c4ca02c35a9fedc24bc982cf75171651e8187c2495ec957a87dfff7",
"sha256:3381ca1a4f37ff1155fcfde20836b46416d66531add8843f6aa6d968982731c3",
"sha256:71c4b330cf2313bbda0307fc858cc9055e64493ba9bf28454d25cf8b3ee8d7f5",
"sha256:f6ebea7c008f155baeefe16c56cd3ee6239f7a5a9ae42396c2f1860f08a7c432",
"sha256:fc575093cf81b6605bed84653e48b277318b880dc9becf42dd47fa11ffd3e2b6"
],
"index": "pypi",
"version": "==2.0.3"
},
"pytz": {
"hashes": [
"sha256:83a4a90894bf38e243cf052c8b58f381bfe9a7a483f6a9cab140bc7f702ac4da",
"sha256:eb10ce3e7736052ed3623d49975ce333bcd712c7bb19a58b9e2089d4057d0798"
],
"version": "==2021.1"
},
"sqlparse": {
"hashes": [
"sha256:017cde379adbd6a1f15a61873f43e8274179378e95ef3fede90b5aa64d304ed0",
"sha256:0f91fd2e829c44362cbcfab3e9ae12e22badaa8a29ad5ff599f9ec109f0454e8"
],
"markers": "python_version >= '3.5'",
"version": "==0.4.1"
}
},
"develop": {}
}

37
README.md

@ -0,0 +1,37 @@
# almalinux.org website
This repository contains website source code for future https://almalinux.org.
This website is built with Python using Django web framework. It uses MariaDB as database backend,
Docker and docker-compose for development environment deployment, and Pipenv is used to track project
requirements, and manage Python dependencies.
JavaScript and SCSS is used for frontend, and is managed/built using Webpack Encore. See
[frontend/README](./frontend/README.md) for more details.
## For developers
To deploy local development environment, you will need following dependencies installed
on your development host:
- Docker
- docker-compose
- make
Common development commands and automation related commands are listed in Makefile. Execute `make help`
for a complete list of available commands.
Executing `make dev` will deploy a complete, ready to go development environment.
### Directories and modules
- `/almalinux/` - Django project root.
- `/commons/` - A Django app-module with reusable utilities for app support.
- `/locale/` - Django locale files.
- `/media/` - Django file uploads.
- `/static/` - Static files and build output for frontend code.
- `/www/` - Django app that contains all logic for the website.
- `/frontend/` - JavaScript and SCSS frontend code.
Copyright (c) 2021 AlmaLinux OS Foundation

0
almalinux/__init__.py

9
almalinux/admin.py

@ -0,0 +1,9 @@
from django.contrib.admin import AdminSite
class AlmaLinuxAdminSite(AdminSite):
site_title = 'AlmaLinux'
site_header = 'AlmaLinux'
def get_urls(self):
return super().get_urls()

5
almalinux/apps.py

@ -0,0 +1,5 @@
from django.contrib.admin.apps import AdminConfig
class AlmaLinuxAdminConfig(AdminConfig):
default_site = 'almalinux.admin.AlmaLinuxAdminSite'

16
almalinux/asgi.py

@ -0,0 +1,16 @@
"""
ASGI config for almalinux project.
It exposes the ASGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/3.1/howto/deployment/asgi/
"""
import os
from django.core.asgi import get_asgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'almalinux.settings')
application = get_asgi_application()

158
almalinux/settings.py

@ -0,0 +1,158 @@
"""
Django settings for almalinux project.
Generated by 'django-admin startproject' using Django 3.1.4.
For more information on this file, see
https://docs.djangoproject.com/en/3.1/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/3.1/ref/settings/
"""
# TODO: .env support for all major settings that could change between envs
from pathlib import Path
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/3.1/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'fm31y+qa5eg74*frj#37_6*cc^g)xg(x(@u(^5m*_qam@_74p!'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = [
'127.0.0.1',
'localhost'
]
# Application definition
INSTALLED_APPS = [
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'commons',
'almalinux.apps.AlmaLinuxAdminConfig',
'www'
]
MIDDLEWARE = [
'django.middleware.locale.LocaleMiddleware',
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF = 'almalinux.urls'
template_loaders = [
'django.template.loaders.filesystem.Loader',
'django.template.loaders.app_directories.Loader'
]
if DEBUG:
effective_loaders = template_loaders
else:
effective_loaders = [
('django.template.loaders.cached.Loader', template_loaders),
]
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': [],
'OPTIONS': {
'loaders': effective_loaders,
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'almalinux.wsgi.application'
# Database
# https://docs.djangoproject.com/en/3.1/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'devel',
'USER': 'devel',
'PASSWORD': 'devel',
'HOST': 'mariadb',
'PORT': 3306,
}
}
# Password validation
# https://docs.djangoproject.com/en/3.1/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# Internationalization
# https://docs.djangoproject.com/en/3.1/topics/i18n/
LANGUAGE_CODE = 'en'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
LANGUAGES = (
('en', 'English (US)'),
('es', 'Español (España)'),
('ru', 'Русский'),
)
LOCALE_PATHS = [
BASE_DIR / 'locale'
]
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.1/howto/static-files/
STATIC_URL = '/static/'
STATICFILES_DIRS = [
BASE_DIR / 'static',
]
ENCORE_BUILD_DIR = BASE_DIR / 'static/build/'
MEDIA_ROOT = BASE_DIR / 'media'
MEDIA_URL = 'media/'

36
almalinux/urls.py

@ -0,0 +1,36 @@
"""almalinux URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/3.1/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.conf import settings
from django.conf.urls.i18n import i18n_patterns
from django.conf.urls.static import static
from django.contrib import admin
from django.urls import path, include
from django.views.i18n import JavaScriptCatalog
urlpatterns = []
urlpatterns += i18n_patterns(path('', include('www.urls')), prefix_default_language=False)
urlpatterns += [
path('admin/', admin.site.urls),
]
urlpatterns += i18n_patterns(path(
'jsi18n/',
JavaScriptCatalog.as_view(),
name='javascript-catalog'
), prefix_default_language=False)
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

16
almalinux/wsgi.py

@ -0,0 +1,16 @@
"""
WSGI config for almalinux project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/3.1/howto/deployment/wsgi/
"""
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'almalinux.settings')
application = get_wsgi_application()

3
commons/__init__.py

@ -0,0 +1,3 @@
from commons.encore import Encore
encore = Encore()

5
commons/apps.py

@ -0,0 +1,5 @@
from django.apps import AppConfig
class CommonsConfig(AppConfig):
name = 'commons'

48
commons/encore.py

@ -0,0 +1,48 @@
import json
from os import path
from django.conf import settings
# Methods in this class should remain non-static as later there might be some instance level cache here.
class Encore:
# noinspection PyMethodMayBeStatic
def load_json(self):
entry_points_path = settings.ENCORE_BUILD_DIR / 'entrypoints.json'
if not path.isfile(entry_points_path):
raise RuntimeError('Missing entry points - %s' % entry_points_path)
with open(entry_points_path) as it:
return json.load(it)
def get_js(self, entrypoint):
data = self.load_json()
if 'entrypoints' not in data:
raise RuntimeError('Invalid entry points manifest')
manifest = data['entrypoints']
if entrypoint not in manifest:
raise RuntimeError('Unknown entrypoint - %s' % entrypoint)
if 'js' not in manifest[entrypoint]:
return []
return manifest[entrypoint]['js']
def get_css(self, entrypoint):
data = self.load_json()
if 'entrypoints' not in data:
raise RuntimeError('Invalid entry points manifest')
manifest = data['entrypoints']
if entrypoint not in manifest:
raise RuntimeError('Unknown entry point - %s' % entrypoint)
if 'css' not in manifest[entrypoint]:
return []
return manifest[entrypoint]['css']

0
commons/templatetags/__init__.py

34
commons/templatetags/encore.py

@ -0,0 +1,34 @@
from django import template
from django.utils.safestring import SafeString
from commons import encore
register = template.Library()
@register.simple_tag()
def encore_entrypoint_js(entrypoint):
js = encore.get_js(entrypoint)
if 0 == len(js):
return ''
buffer = ''
for script in js:
buffer += '<script src="%s" defer></script>\n' % script
return SafeString(buffer.strip())
@register.simple_tag
def encore_entrypoint_css(entrypoint):
css = encore.get_css(entrypoint)
if 0 == len(css):
return ''
buffer = ''
for stylesheet in css:
buffer += '<link rel="stylesheet" href="%s">' % stylesheet
return SafeString(buffer.strip())

23
commons/uploads.py

@ -0,0 +1,23 @@
import hashlib
from os import path
# This method allows for file uploads to live in segmented folders,
# instead of placing all uploads in a single folder.
# noinspection PyUnusedLocal
def segmented_upload_to(instance, file_name) -> str:
"""
:param instance:
:param file_name: string
"""
filename_base, filename_ext = path.splitext(file_name)
filename_base = filename_base.replace('/', '_')
hashcode = hashlib.md5(filename_base.encode()).hexdigest()
return '{0}/{1}/{2}/{3}{4}'.format(
hashcode[0:2],
hashcode[2:4],
hashcode[4:6],
filename_base,
filename_ext
)

50
docker-compose.yml

@ -0,0 +1,50 @@
version: '3'
services:
web:
container_name: web
build:
context: .
args:
LOCAL_UID: ${LOCAL_UID}
LOCAL_GID: ${LOCAL_GID}
restart: 'no'
links:
- mariadb
- frontend
volumes:
- .:/app/
ports:
- 8080:8080 # HTTP
frontend:
container_name: frontend
build:
context: .
dockerfile: Dockerfile-frontend
args:
LOCAL_UID: ${LOCAL_UID}
LOCAL_GID: ${LOCAL_GID}
restart: 'no'
volumes:
- .:/app/
ports:
- 8090:8090 # HTTP devserver
mariadb:
image: mariadb:10
container_name: mariadb
restart: 'no'
environment:
MYSQL_ROOT_PASSWORD: devel
MYSQL_DATABASE: devel
MYSQL_USER: devel
MYSQL_PASSWORD: devel
volumes:
- mariadb:/var/lib/mysql
ports:
- 3306:3306
volumes:
mariadb:
driver: local

1
frontend/.gitignore

@ -0,0 +1 @@
node_modules

41
frontend/README.md

@ -0,0 +1,41 @@
# almalinux.org JavaScript and SCSS modules
This source module contains frontend specific source code for almalinux.org.
- NodeJS v15.
- Yarn for dependency management.
- Modern JavaScript.
- SCSS for stylesheets.
## Source structure
All CSS/JS code can be found in `src/` directory.
### `src/common`
Common entry point is used for JavaScript and SCSS code that is expected to be used by all or most of the website pages,
and for otherwise reusable code.
### `src/modules`
Modules root directory contains modular JS/SCSS for features isolate to some specific domain, such as a specific feature
or page. Features should be generally organized following this convention:
```
src/modules/feature_<NAME>
src/modules/page_<NAME>
```
The difference between `page_*` and `feature_*` is that page specific code is limited to be used within a single view,
while features should be reusable.
Each module should contain a README.md file to document features, use and dependencies for said specific code module.
`<NAME>` identifiers should be short, but descriptive, and should follow pattern `[a-z_]+`.
#### Dependencies within modules
- `page_*` is allowed to have zero or more dependencies on `feature_*` modules, or code in `src/common`
- `page_*` must not depend on code in another `_page*`
- `feature_*` can depend on another `feature_*`.

29
frontend/package.json

@ -0,0 +1,29 @@
{
"license": "MIT",
"private": true,
"scripts": {
"dev-server": "encore dev-server --hot",
"dev": "encore dev",
"build": "encore production --progress"
},
"browserslist": [
"> 0.5%",
"last 2 versions",
"Firefox ESR",
"not dead"
],
"devDependencies": {
"@babel/preset-env": "^7.14.1",
"@symfony/webpack-encore": "^1.2.0",
"autoprefixer": "^10.2.5",
"babel-core": "^6.26.3",
"babel-loader": "^8.2.2",
"core-js": "^3.11.2",
"eslint": "^7.25.0",
"node-sass": "^5.0.0",
"normalize.css": "^8.0.1",
"postcss-loader": "^5.2.0",
"sass-loader": "^11.0.1"
},
"dependencies": {}
}

5
frontend/postcss.config.js

@ -0,0 +1,5 @@
module.exports = {
plugins: {
autoprefixer: {},
}
}

3
frontend/src/common/js/main.js

@ -0,0 +1,3 @@
import '@common/scss/main.scss';
console.log(gettext('Hello World'));

2
frontend/src/common/scss/main.scss

@ -0,0 +1,2 @@
@import "~normalize.css";

18
frontend/src/django.mock.js

@ -0,0 +1,18 @@
// This file is to mock django frontend localization API for intellisense. You do not need to include it in source.
// noinspection JSUnusedLocalSymbols
window.pluralidx = window.pluralidx || function (n) {
};
window.gettext = window.gettext || function (msgid) {
};
window.ngettext = window.ngettext || function (singular, plural, count) {
};
window.gettext_noop = window.gettext_noop || function (msgid) {
};
window.pgettext = window.pgettext || function (context, msgid) {
};
window.npgettext = window.npgettext || function (context, singular, plural, count) {
};
window.interpolate = window.interpolate || function (fmt, obj, named) {
};
window.get_format = window.get_format || function (format_type) {
};

0
frontend/src/modules/.gitignore

47
frontend/webpack.config.js

@ -0,0 +1,47 @@
const path = require('path');
const Encore = require('@symfony/webpack-encore');
if (!Encore.isRuntimeEnvironmentConfigured()) {
Encore.configureRuntimeEnvironment(process.env.NODE_ENV || 'dev');
}
if (Encore.isProduction()) {
process.env.NODE_ENV = 'production';
}
const BUILD_DIR = path.normalize(__dirname + '/../static/build/')
Encore
.setOutputPath(BUILD_DIR)
.setPublicPath('/static/build')
.splitEntryChunks()
.enableSingleRuntimeChunk()
.cleanupOutputBeforeBuild()
.enablePostCssLoader()
.enableSourceMaps(!Encore.isProduction())
.enableVersioning(Encore.isProduction())
.configureBabel((config) => {
})
.configureBabelPresetEnv((config) => {
config.useBuiltIns = 'usage';
config.corejs = 3;
})
.enableSassLoader()
.configureDevServerOptions((config) => {
config.static = false;
})
// Common CSS and JavaScript for the whole website
.addEntry('common', __dirname + '/src/common/js/main.js')
;
if (Encore.isDevServer() || Encore.isDev()) {
Encore.disableCssExtraction();
}
Encore.addAliases({
'@common': path.resolve(__dirname, 'src/common/'),
'@modules': path.resolve(__dirname, 'src/modules/')
})
module.exports = Encore.getWebpackConfig();

6300
frontend/yarn.lock

File diff suppressed because it is too large

22
locale/es/LC_MESSAGES/django.po

@ -0,0 +1,22 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-05-05 15:11+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: es\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: www/templates/index.html:5
msgid "Hello World"
msgstr "Hola Mundo"

22
locale/es/LC_MESSAGES/djangojs.po

@ -0,0 +1,22 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-05-05 15:06+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: es\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: frontend/src/common/js/main.js:3
msgid "Hello World"
msgstr "Hola Mundo"

20
locale/ru/LC_MESSAGES/django.po

@ -0,0 +1,20 @@
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: almalinuxorg/1.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-05-05 13:46+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: ru\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
"%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n"
"%100>=11 && n%100<=14)? 2 : 3);\n"
#: www/templates/index.html:3
msgid "Hello World"
msgstr "Привет мир"

20
locale/ru/LC_MESSAGES/djangojs.po

@ -0,0 +1,20 @@
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: almalinuxorg/1.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-05-05 14:23+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: ru\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
"%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n"
"%100>=11 && n%100<=14)? 2 : 3);\n"
#: frontend/src/common/js/main.js:1
msgid "Hello World"
msgstr "Привет мир"

22
manage.py

@ -0,0 +1,22 @@
#!/usr/bin/env python
"""Django's command-line utility for administrative tasks."""
import os
import sys
def main():
"""Run administrative tasks."""
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'almalinux.settings')
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?"
) from exc
execute_from_command_line(sys.argv)
if __name__ == '__main__':
main()

2
media/.gitignore

@ -0,0 +1,2 @@
*
!.gitignore

0
static/.gitignore

0
www/__init__.py

15
www/admin.py

@ -0,0 +1,15 @@
from django.contrib import admin
# from django.conf.urls import url
# Register your models here.
# admin.site.register(...)
# Admin customizations
frontpage_admin_urls = [
# url(r'^tweet/process/$', admin.site.admin_view(...CUSTOM_ADMIN_VIEW))
]
_original_urls_reader = admin.site.get_urls
admin.site.get_urls = lambda: (_original_urls_reader() + frontpage_admin_urls)

5
www/apps.py

@ -0,0 +1,5 @@
from django.apps import AppConfig
class WWWConfig(AppConfig):
name = 'www'

0
www/migrations/__init__.py

1
www/models.py

@ -0,0 +1 @@
# Create your models here.

6
www/templates/index.html

@ -0,0 +1,6 @@
{% extends 'layouts/base.html' %}
{% load i18n %}
{% block body %}
<span>{% translate "Hello World" %}</span>
{% endblock %}

20
www/templates/layouts/base.html

@ -0,0 +1,20 @@
{% load encore %}
{% load static %}
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"
name="viewport">
<meta content="ie=edge" http-equiv="X-UA-Compatible">
<title>{% block title %}AlmaLinux{% endblock %}</title>
{% encore_entrypoint_css 'common' %}
{% block head_end %}{% endblock %}
</head>
<body>
{% block body %}{% endblock %}
<script src="{% url 'javascript-catalog' %}" defer></script>
{% encore_entrypoint_js 'common' %}
{% block body_end %}{% endblock %}
</body>
</html>

1
www/tests.py

@ -0,0 +1 @@
# Create your tests here.

7
www/urls.py

@ -0,0 +1,7 @@
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='index'),
]

6
www/views.py

@ -0,0 +1,6 @@
from django.http import HttpResponse, HttpRequest
from django.shortcuts import render
def index(request: HttpRequest) -> HttpResponse:
return render(request, 'index.html')
Loading…
Cancel
Save