Initial commit

This commit is contained in:
Scott Wallace 2022-05-02 13:44:10 +01:00
commit 9acde4bd9d
Signed by: scott
GPG key ID: AA742FDC5AFE2A72
7 changed files with 154 additions and 0 deletions

1
.dockerignore Symbolic link
View file

@ -0,0 +1 @@
.gitignore

3
.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
__pycache__/
.mypy_cache/
.pyenv/

44
.gitlab-ci.yml Normal file
View file

@ -0,0 +1,44 @@
# This file is a template, and might need editing before it works on your project.
# To contribute improvements to CI/CD templates, please follow the Development guide at:
# https://docs.gitlab.com/ee/development/cicd/templates.html
# This specific template is located at:
# https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Getting-Started.gitlab-ci.yml
# This is a sample GitLab CI/CD configuration file that should run without any modifications.
# It demonstrates a basic 3 stage CI/CD pipeline. Instead of real tests or scripts,
# it uses echo commands to simulate the pipeline execution.
#
# A pipeline is composed of independent jobs that run scripts, grouped into stages.
# Stages run in sequential order, but jobs within stages run in parallel.
#
# For more information, see: https://docs.gitlab.com/ee/ci/yaml/index.html#stages
before_script:
- pip install -Ur requirements.txt
stages: # List of stages for jobs, and their order of execution
- test
- build
build-job: # This job runs in the build stage, which runs first.
stage: build
script:
- echo "Building the Docker image..."
- echo $CI_REGISTRY_PASSWORD | docker login -u $CI_REGISTRY_USER $CI_REGISTRY --password-stdin
- docker build -t $CI_REGISTRY_IMAGE .
- docker push $CI_REGISTRY_IMAGE
- echo "Build complete."
unit-test-job: # This job runs in the test stage.
stage: test
script:
- echo "Running unit tests..."
- python3 -munittest discover
- echo "Testing complete"
lint-test-job: # This job also runs in the test stage.
stage: test # It can run at the same time as unit-test-job (in parallel).
script:
- echo "Linting code..."
- pylint -j0 -v $(git ls-files '*.py')
- echo "No lint issues found."

34
Dockerfile Normal file
View file

@ -0,0 +1,34 @@
# Build an intermediate image for the Python requirements
FROM python:3.9-slim-buster as intermediate
# Install Git and Python requirements
RUN apt update && apt install -y build-essential
COPY requirements.txt .
RUN python -m pip install --user -r requirements.txt pip
# Start from a fresh image
FROM python:3.9-slim-buster
# Keeps Python from generating .pyc files in the container
ENV PYTHONDONTWRITEBYTECODE=1
# Turns off buffering for easier container logging
ENV PYTHONUNBUFFERED=1
RUN useradd -u 4000 -d /app appuser
WORKDIR /app
# Copy over the Python requirements from the intermediate container
COPY --from=intermediate /root/.local /app/.local
RUN chown -R appuser: /app
USER appuser
# Set the main execution command
ENTRYPOINT [".local/bin/waitress-serve", "main:app"]
# HEALTHCHECK --interval=5s --timeout=30s --start-period=5s --retries=3 CMD [ "/app/healthcheck.sh" ]
EXPOSE 8080/tcp
# Copy in the code
COPY main.py .

9
docker-compose.yaml Normal file
View file

@ -0,0 +1,9 @@
---
version: "3"
services:
ical_offset:
container_name: ical_offset
build:
context: .
image: ical_offset:latest
restart: unless-stopped

59
main.py Normal file
View file

@ -0,0 +1,59 @@
"""
Take existing calendar and update it slightly
"""
from datetime import datetime, time, timedelta
import requests
from flask import Flask, Response, request
from icalendar import Calendar, Event # type: ignore[import]
from werkzeug.middleware.proxy_fix import ProxyFix
app = Flask(__name__)
app.wsgi_app = ProxyFix(app.wsgi_app, x_proto=1) # type: ignore[assignment]
@app.route('/', methods=['get'])
def process() -> Response:
"""
Fetch ICS url and convert from Events to Todos
Returns:
Response: ical response
"""
# Fetch existing calendar
orig = requests.get(request.args['url'])
days = request.args.get('days', '0')
hours = request.args.get('hours', '0')
mins = request.args.get('mins', '0')
orig_cal = Calendar.from_ical(orig.text)
cal = Calendar()
cal.add('version', '2.0')
cal.add(
'prodid',
'-//Scott Wallace//event2task//EN',
)
for component in orig_cal.subcomponents:
if isinstance(component, Event):
entry = Event()
entry.add('description', component['description'])
entry.add('dtstamp', component['dtstamp'])
# entry.add('dtstart', component['dtstart'])
entry.add(
'dtstart',
datetime.combine(component.decoded('dtstart'), time(0))
+ timedelta(days=int(days), hours=int(hours), minutes=int(mins)),
)
entry.add('summary', component['summary'])
entry.add('uid', component['uid'])
cal.add_component(entry)
return Response(
cal.to_ical().decode().replace('\\r\\n', '\n').strip(),
headers={'content-type': 'text/calendar; charset=UTF-8'},
)

4
requirements.txt Normal file
View file

@ -0,0 +1,4 @@
icalendar
flask
requests
waitress