Initial commit
This commit is contained in:
commit
9acde4bd9d
1
.dockerignore
Symbolic link
1
.dockerignore
Symbolic link
|
@ -0,0 +1 @@
|
|||
.gitignore
|
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
__pycache__/
|
||||
.mypy_cache/
|
||||
.pyenv/
|
44
.gitlab-ci.yml
Normal file
44
.gitlab-ci.yml
Normal 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
34
Dockerfile
Normal 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
9
docker-compose.yaml
Normal 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
59
main.py
Normal 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
4
requirements.txt
Normal file
|
@ -0,0 +1,4 @@
|
|||
icalendar
|
||||
flask
|
||||
requests
|
||||
waitress
|
Loading…
Reference in a new issue