Skip to content

Commit

Permalink
Merge branch 'develop' into 'master'
Browse files Browse the repository at this point in the history
Release 0.19.0

See merge request prod-manager/prod-manager!125

Signed-off-by: Lunik <[email protected]>
  • Loading branch information
Lunik committed Feb 5, 2023
2 parents 7562bca + 9d0d623 commit f2e02c2
Show file tree
Hide file tree
Showing 63 changed files with 1,833 additions and 88 deletions.
4 changes: 2 additions & 2 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,7 @@ stages:
- python --version # For debugging
- python -m venv venv
- source venv/bin/activate
- pip install -r requirements.dev.txt
- pip install -r requirements.txt
- pip install --upgrade -r requirements.txt -r requirements.dev.txt

test:
extends: .python-tests
Expand Down Expand Up @@ -294,6 +293,7 @@ dast:
/monitor
/incident
/maintenance
/announcement
/about
/login
EOF
Expand Down
17 changes: 17 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,22 @@
# CHANGELOG

## 0.19.0

## Added

- feat(announcement): Add support for Announcements (#165) (!127)
- feat(markdown): Add support for Markdown syntaxe in resources description (!130)
- feat(forms.\*): Add placeholder in forms textarea inputs (!131)

## Fixed

- fix(mail): Simplify CSS in mail notification (#166) (!126)
- fix(mail): Remove default trailing space in mail object prefix (!128)
- fix(docs): Missing Maintenance status in API documentation (!129)
- fix(database): Fix SQLAlchemy deprecation warnings (#167) (!132)
- fix(ci): Fix DAST_API in CI (!133)


## 0.18.1

## Added
Expand Down
12 changes: 12 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,18 @@ To include an icon in template, you need to use only the `icon` macro like :
{{ icon('dashboard') }}
```

### Code snippet in resource description

In resource description, the user can put code using "fenced-code" that will by formated and colored :
- [Fenced-code extention](https://python-markdown.github.io/extensions/fenced_code_blocks/)
- [Code highligh extention](https://python-markdown.github.io/extensions/code_hilite/)

Code highlinting theme is generated with [pygmentize](https://pygments.org) with the following command :
```bash
pygmentize -S default -f html -a .codehilite > ProdManager/static/css/codehilite.css
```
The `default` theme is used, but other can be found in [Pygments the style section](https://pygments.org/styles/)

## Translation

The application has multilang support. This means that every string printed to the final user (except log output) should sould support translation.
Expand Down
7 changes: 2 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,7 @@ help:
@echo ' '

install: env
${VENV_PY} -m pip install -r "${REQUIREMENTS}"

install-dev: env
${VENV_PY} -m pip install -r "${REQUIREMENTS_DEV}"
${VENV_PY} -m pip install --upgrade -r "${REQUIREMENTS}" -r "${REQUIREMENTS_DEV}"

install-docker:
${PY} -m pip install --no-cache-dir --compile -r "${REQUIREMENTS}"
Expand Down Expand Up @@ -100,7 +97,7 @@ lint:
${PYLINT} ${PACKAGE_NAME}/* | tee pylint-report.txt

test: local-database-cleanup demo-data-dev
${VENV_PY} -m pytest -v -n 4 --cov=${PACKAGE_NAME} --junitxml=result.xml --html=report.html tests/${PACKAGE_NAME}/ \
${VENV_PY} -m pytest -vv -n 4 --cov=${PACKAGE_NAME} --junitxml=result.xml --html=report.html tests/${PACKAGE_NAME}/ \
&& ${COVERAGE} xml \
&& ${COVERAGE} html

Expand Down
14 changes: 9 additions & 5 deletions ProdManager/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

from ProdManager.helpers.config import boolean_param
from .plugins import (
db, migrate, csrf, mail, lang, redis_client
db, migrate, csrf, mail, lang, redis_client, markdown
)

def create_app():
Expand Down Expand Up @@ -52,7 +52,7 @@ def create_app():
MAIL_VALIDATE_CERTS=boolean_param(os.environ.get("PM_MAIL_VALIDATE_CERTS", 'True')),
MAIL_USE_CREDENTIALS=boolean_param(os.environ.get("PM_MAIL_USE_CREDENTIALS", 'True')),
MAIL_SENDER=os.environ.get("PM_MAIL_SENDER", None),
MAIL_PREFIX=os.environ.get("PM_MAIL_PREFIX", "[ProdManager] "),
MAIL_PREFIX=os.environ.get("PM_MAIL_PREFIX", "[ProdManager]"),
MAIL_REPLY_TO=os.environ.get("PM_MAIL_REPLY_TO", None),
LANG=os.environ.get("PM_LANG", "en"),
DEBUG=boolean_param(os.environ.get("PM_DEBUG", 'False')),
Expand Down Expand Up @@ -110,6 +110,7 @@ def pre_response(response):

mail.init_app(app)
lang.init_app(app)
markdown.init_app(app)

# apply Gunicorn logger config
gunicorn_logger = logging.getLogger('gunicorn.error')
Expand All @@ -132,14 +133,14 @@ def pre_response(response):

from ProdManager.models import (
Incident, IncidentEvent, Maintenance, MaintenanceEvent,
Monitor, Subscriber, Scope, Service,
Monitor, Subscriber, Scope, Service, Announcement
)


from ProdManager.routes import (
root, auth, scope, service, incident,
maintenance, monitor, health, notification,
weather, token
weather, token, announcement
)
# apply the blueprints to the app
app.register_blueprint(root.view, url_prefix="/")
Expand All @@ -158,10 +159,12 @@ def pre_response(response):
app.register_blueprint(health.view, url_prefix="/health")
app.register_blueprint(notification.view, url_prefix="/notification")
app.register_blueprint(weather.view, url_prefix="/api/weather", name="weather_api")
app.register_blueprint(announcement.view, url_prefix="/announcement")
app.register_blueprint(announcement.view, url_prefix="/api/announcement", name="announcement_api")

from ProdManager.helpers.jinja2 import (
ternary, format_column_name, format_timeline_date,
format_template_name, is_it_winter
format_template_name, is_it_winter, include_file
)
from ProdManager.helpers.pagination import url_for_paginated
from ProdManager.helpers.links import custom_url_for
Expand All @@ -177,6 +180,7 @@ def pre_response(response):
app.jinja_env.globals['_'] = text
app.jinja_env.globals['is_it_winter'] = is_it_winter
app.jinja_env.globals['get_resource_view'] = get_resource_view
app.jinja_env.globals['include_file'] = include_file


return app
23 changes: 22 additions & 1 deletion ProdManager/demo/init.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import random
from datetime import datetime

from sqlalchemy.orm import Session
from flask import g

from ProdManager.plugins import db
Expand Down Expand Up @@ -281,3 +280,25 @@
type=EventType.COMMENT,
internal=False,
))

# ANNOUNCEMENTS
create_resource(Announcement, dict(
name="Object storage backend migration",
description="We are planning to migrate the actual backend for the object storage service.\nExpect some degraded performance during the comming days",
level=AnnouncementLevel.MEDIUM,
scope_id=2,
service_id=3,
creation_date=datetime.strptime("2023-02-05T10:22", DATETIME_FORMAT),
start_date=datetime.strptime("2023-02-06T08:00", DATETIME_FORMAT),
end_date=datetime.strptime("2023-02-12T22:00", DATETIME_FORMAT),
))
create_resource(Announcement, dict(
name="End of support of Python 2.9 in Serveless functions",
description="Python 2.9 option will soon be unavailable to select when creating new serveless functions.\nThis change take effect on 01/03/2023 at 00:00. [More informations](https://peps.python.org/pep-0373/#references)",
level=AnnouncementLevel.HIGH,
scope_id=1,
service_id=7,
creation_date=datetime.strptime("2023-02-05T10:22", DATETIME_FORMAT),
start_date=datetime.strptime("2023-01-15T08:00", DATETIME_FORMAT),
end_date=datetime.strptime("2023-03-15T22:00", DATETIME_FORMAT),
))
9 changes: 7 additions & 2 deletions ProdManager/helpers/form.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,16 @@ def strip_input(content):
raise Exception(f"Type not handled : {content.__class__.__name__}")

result = []
previous_line = None
for line in content.split('\n'):
line = line.strip()
if line != "":
line = line.rstrip()

# Remove useless 2 or more new line in chain
if line or previous_line != "":
result.append(line)

previous_line = line

return '\n'.join(result)

class CustomForm(FlaskForm):
Expand Down
17 changes: 16 additions & 1 deletion ProdManager/helpers/jinja2.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import re
import logging
from datetime import datetime
from flask import current_app

from ProdManager.helpers.date import beautifull_date

logger = logging.getLogger('gunicorn.error')

def ternary(expr, value_a, value_b):
return value_a if expr else value_b

Expand All @@ -23,4 +27,15 @@ def format_template_name(key, keep="folder"):

def is_it_winter():
now = datetime.utcnow()
return now >= winter_dates[0] and now <= winter_dates[1]
return now >= winter_dates[0] and now <= winter_dates[1]

def include_file(name):
content = b""

try:
with current_app.open_resource(name) as file:
content = file.read()
except Exception as error:
logger.error(error)

return content.decode('UTF-8')
37 changes: 37 additions & 0 deletions ProdManager/helpers/lang/translations/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,27 @@ maintenance_update_notification_title: ["Updated ", *maintenance_name]
maintenance_comment_failed: [*maintenance_title, " comment failed"]
maintenance_deletion_failed: [*maintenance_title, " deletion failed"]

# Announcement
announcement_name: &announcement_name announcement
announcement_title: &announcement_title Announcement

announcement_ongoing: ["Ongoing ", *announcement_name, "s"]

announcement_start: from
announcement_end: until

announcement_level_high: HIGH
announcement_level_medium: MEDIUM
announcement_level_low: LOW

announcement_creation_failed: [*announcement_title, " creation failed"]
announcement_create_notification_title: ["New ", *announcement_name]
announcement_show_failed: [*announcement_title, " show failed"]
announcement_update_failed: [*announcement_title, " update failed"]
announcement_update_notification_title: ["Updated ", *announcement_name]
announcement_comment_failed: [*announcement_title, " comment failed"]
announcement_deletion_failed: [*announcement_title, " deletion failed"]

# Subscribe
notification_title: &notification_title Notification
notification_name: &notification_name notification
Expand Down Expand Up @@ -230,6 +251,13 @@ resource_update_maintenance: ["Update ", *maintenance_name]
resource_comment_maintenance: ["Add a comment to the ", *maintenance_name]
resource_delete_maintenance: ["Delete ", *maintenance_name]

## Announcement
resource_announcement: *announcement_title
resource_back_to_list_announcement: ["Back to ", *announcement_name, "s list"]
resource_update_announcement: ["Update ", *announcement_name]
resource_comment_announcement: ["Add a comment to the ", *announcement_name]
resource_delete_announcement: ["Delete ", *announcement_name]


# Resource filters
filters_title: Filters
Expand Down Expand Up @@ -260,6 +288,10 @@ resource_list_create_incident: ["Create new ", *incident_name]
resource_list_maintenance: [*maintenance_title, "s list"]
resource_list_create_maintenance: ["Create new ", *maintenance_name]

## Announcement
resource_list_announcement: [*announcement_title, "s list"]
resource_list_create_announcement: ["Create new ", *announcement_name]


# Errors
error_title: Error
Expand All @@ -283,6 +315,7 @@ table_column_scope: *scope_name
table_column_service: *service_name
table_column_severity: severity
table_column_status: status
table_column_level: level
table_column_service_status: service status
table_column_external_reference: external reference
table_column_start_impact_date: start impact date
Expand All @@ -306,6 +339,10 @@ table_column_secret: secret
table_column_not_before_date: not before date
table_column_expiration_date: expiration date

# Inputs
placeholder_input_description: Description content support Markdown syntaxe
placeholder_input_comment: Comment content support Markdown syntaxe

# Pagination
pagination_overflow: Pagination value overflow

Expand Down
33 changes: 33 additions & 0 deletions ProdManager/helpers/lang/translations/fr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,25 @@ maintenance_update_notification_title: ["Mise à jour de la ", *maintenance_name
maintenance_comment_failed: ["Commentaire de la ", *maintenance_name, " échoué"]
maintenance_deletion_failed: ["Suppression de la ", *maintenance_name, " échouée"]

# Announcement
announcement_name: &announcement_name annonce
announcement_title: &announcement_title Annonce

announcement_ongoing: [*announcement_name, "s en cours"]

announcement_start: depuis
announcement_end: jusqu'a

announcement_level_high: HAUT
announcement_level_medium: MOYEN
announcement_level_low: BAS

announcement_creation_failed: ["Création de l'", *announcement_name, " échouée"]
announcement_create_notification_title: ["Nouvel ", *announcement_name]
announcement_show_failed: ["Affichage de l'", *announcement_name, " échoué"]
announcement_update_failed: ["Mise à jour de l'", *announcement_name, " échouée"]
announcement_update_notification_title: ["Mise à jour de l'", *announcement_name]
announcement_deletion_failed: ["Suppression de l'", *announcement_name, " échouée"]

# Subscribe
notification_title: &notification_title Notification
Expand Down Expand Up @@ -224,6 +243,11 @@ resource_update_maintenance: ["Mettre à jour la ", *maintenance_name]
resource_comment_maintenance: ["Ajouter un commentaire sur la ", *maintenance_name]
resource_delete_maintenance: ["Supprimer la ", *maintenance_name]

## Announcement
resource_announcement: *announcement_title
resource_back_to_list_announcement: ["Retour à la liste d'", *announcement_name, "s"]
resource_update_announcement: ["Mettre à jour l'", *announcement_name]
resource_delete_announcement: ["Supprimer l'", *announcement_name]

# Resource filters
filters_title: Filtres
Expand Down Expand Up @@ -254,6 +278,10 @@ resource_list_create_incident: ["Créer un nouvel ", *incident_name]
resource_list_maintenance: ["Liste des ", *maintenance_name, "s"]
resource_list_create_maintenance: ["Créer une nouvelle ", *maintenance_name]

## Announcement
resource_list_announcement: ["Liste des ", *announcement_name, "s"]
resource_list_create_announcement: ["Créer un nouvel ", *announcement_name]


# Errors
error_title: Erreur
Expand All @@ -276,6 +304,7 @@ table_column_scope: *scope_name
table_column_service: *service_name
table_column_severity: sévérité
table_column_status: statut
table_column_level: niveau
table_column_service_status: statut du service
table_column_external_reference: référence externe
table_column_start_impact_date: date de début d'impact
Expand All @@ -299,6 +328,10 @@ table_column_secret: secret
table_column_not_before_date: date de début de validité
table_column_expiration_date: date d'expiration

# Inputs
placeholder_input_description: Le contenu de la description supporte la syntaxe Markdown
placeholder_input_comment: Le contenu du commentaire supporte la syntaxe Markdown

# Pagination
pagination_overflow: Débordement de valeur de pagination

Expand Down
29 changes: 29 additions & 0 deletions ProdManager/helpers/markdown.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from flask import Markup
from markupsafe import escape
from jinja2 import pass_eval_context
import markdown as md

class Markdown:
def __init__(self, app=None, auto_escape=False, **markdown_options):
self.auto_escape = auto_escape
self._instance = md.Markdown(**markdown_options)
if app:
self.init_app(app)

def init_app(self, app):
app.jinja_env.filters.setdefault(
'markdown', self.__build_filter(self.auto_escape))

def __call__(self, stream):
return Markup(self._instance.convert(stream))

def __build_filter(self, app_auto_escape):
@pass_eval_context
def markdown_filter(eval_ctx, stream):
__filter = self
if app_auto_escape and eval_ctx.autoescape:
return Markup(__filter(escape(stream)))

return Markup(__filter(stream))

return markdown_filter
Loading

0 comments on commit f2e02c2

Please sign in to comment.