Merge pull request #7 from cccb/staging-to-prod
WIP: Switch on new homepage in prod
This commit is contained in:
		
						commit
						0ca6400f2a
					
				
					 24 changed files with 450 additions and 261 deletions
				
			
		
							
								
								
									
										19
									
								
								.editorconfig
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								.editorconfig
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,19 @@
 | 
				
			||||||
 | 
					# EditorConfig is awesome: https://EditorConfig.org
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# top-most EditorConfig file
 | 
				
			||||||
 | 
					root = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Unix-style newlines with a newline ending every file
 | 
				
			||||||
 | 
					[*]
 | 
				
			||||||
 | 
					charset = utf-8
 | 
				
			||||||
 | 
					end_of_line = lf
 | 
				
			||||||
 | 
					insert_final_newline = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[*.py]
 | 
				
			||||||
 | 
					indent_style = space
 | 
				
			||||||
 | 
					indent_size = 4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[*.yaml]
 | 
				
			||||||
 | 
					indent_style = space
 | 
				
			||||||
 | 
					indent_size = 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										1
									
								
								.github/CODEOWNERS
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								.github/CODEOWNERS
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1 @@
 | 
				
			||||||
 | 
					* @cccb/web
 | 
				
			||||||
							
								
								
									
										28
									
								
								.github/dependabot.yml
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								.github/dependabot.yml
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,28 @@
 | 
				
			||||||
 | 
					# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					version: 2
 | 
				
			||||||
 | 
					updates:
 | 
				
			||||||
 | 
					  - package-ecosystem: "github-actions"
 | 
				
			||||||
 | 
					    directory: "/"
 | 
				
			||||||
 | 
					    target-branch: "staging"
 | 
				
			||||||
 | 
					    schedule:
 | 
				
			||||||
 | 
					      interval: "weekly"
 | 
				
			||||||
 | 
					    commit-message:
 | 
				
			||||||
 | 
					      prefix: "gh-action"
 | 
				
			||||||
 | 
					    labels:
 | 
				
			||||||
 | 
					      - "gh-action"
 | 
				
			||||||
 | 
					      - "dependencies"
 | 
				
			||||||
 | 
					    reviewers:
 | 
				
			||||||
 | 
					      - "cccb/web"
 | 
				
			||||||
 | 
					  - package-ecosystem: "pip"
 | 
				
			||||||
 | 
					    directory: "/"
 | 
				
			||||||
 | 
					    target-branch: "dev"
 | 
				
			||||||
 | 
					    schedule:
 | 
				
			||||||
 | 
					      interval: "weekly"
 | 
				
			||||||
 | 
					    commit-message:
 | 
				
			||||||
 | 
					      prefix: "python"
 | 
				
			||||||
 | 
					    labels:
 | 
				
			||||||
 | 
					      - "python"
 | 
				
			||||||
 | 
					      - "dependencies"
 | 
				
			||||||
 | 
					    reviewers:
 | 
				
			||||||
 | 
					      - "cccb/web"
 | 
				
			||||||
							
								
								
									
										126
									
								
								.github/workflows/release.yml
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								.github/workflows/release.yml
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,126 @@
 | 
				
			||||||
 | 
					name: Release website
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					on:
 | 
				
			||||||
 | 
					  push:
 | 
				
			||||||
 | 
					    branches:
 | 
				
			||||||
 | 
					      - staging
 | 
				
			||||||
 | 
					      - production
 | 
				
			||||||
 | 
					  pull_request:
 | 
				
			||||||
 | 
					  workflow_dispatch:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					jobs:
 | 
				
			||||||
 | 
					  pages:
 | 
				
			||||||
 | 
					    runs-on: ubuntu-latest
 | 
				
			||||||
 | 
					    steps:
 | 
				
			||||||
 | 
					      - name: Checkout
 | 
				
			||||||
 | 
					        uses: actions/checkout@v3
 | 
				
			||||||
 | 
					        with:
 | 
				
			||||||
 | 
					          submodules: recursive
 | 
				
			||||||
 | 
					          fetch-depth: 0
 | 
				
			||||||
 | 
					      - name: Setup Hugo
 | 
				
			||||||
 | 
					        uses: peaceiris/actions-hugo@v2
 | 
				
			||||||
 | 
					        with:
 | 
				
			||||||
 | 
					          hugo-version: 'latest'
 | 
				
			||||||
 | 
					      - name: Build pages
 | 
				
			||||||
 | 
					        run: hugo $(cat .hugo-params)
 | 
				
			||||||
 | 
					      - uses: actions/upload-artifact@v3
 | 
				
			||||||
 | 
					        name: Upload pages
 | 
				
			||||||
 | 
					        with:
 | 
				
			||||||
 | 
					          name: pages
 | 
				
			||||||
 | 
					          path: public
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  calendar:
 | 
				
			||||||
 | 
					    needs: [ pages ]
 | 
				
			||||||
 | 
					    runs-on: ubuntu-latest
 | 
				
			||||||
 | 
					    steps:
 | 
				
			||||||
 | 
					      - name: Add de_DE.UTF-8 locale
 | 
				
			||||||
 | 
					        run: |
 | 
				
			||||||
 | 
					          sudo apt-get update
 | 
				
			||||||
 | 
					          sudo apt-get -y install locales
 | 
				
			||||||
 | 
					          sudo locale-gen de_DE.UTF-8
 | 
				
			||||||
 | 
					      - name: Checkout
 | 
				
			||||||
 | 
					        uses: actions/checkout@v3
 | 
				
			||||||
 | 
					        with:
 | 
				
			||||||
 | 
					          submodules: recursive
 | 
				
			||||||
 | 
					          fetch-depth: 0
 | 
				
			||||||
 | 
					      - name: Setup Python
 | 
				
			||||||
 | 
					        uses: actions/setup-python@v4
 | 
				
			||||||
 | 
					        with:
 | 
				
			||||||
 | 
					          cache: 'pip' # caching pip dependencies
 | 
				
			||||||
 | 
					      - name: Install dependencies
 | 
				
			||||||
 | 
					        run: |
 | 
				
			||||||
 | 
					          pip install --upgrade pip setuptools wheel
 | 
				
			||||||
 | 
					          pip install -r requirements.txt
 | 
				
			||||||
 | 
					      - name: Download pages
 | 
				
			||||||
 | 
					        uses: actions/download-artifact@v3
 | 
				
			||||||
 | 
					        with:
 | 
				
			||||||
 | 
					          name: pages
 | 
				
			||||||
 | 
					          path: public/
 | 
				
			||||||
 | 
					      - name: Generate calendars
 | 
				
			||||||
 | 
					        run: python tools/merge_cals.py
 | 
				
			||||||
 | 
					      - name: Copy calendar to output dir
 | 
				
			||||||
 | 
					        run: cp static/all.ics public/all.ics
 | 
				
			||||||
 | 
					      - name: Update homepage with latest event
 | 
				
			||||||
 | 
					        run: upcoming="$(python tools/gen_upcoming.py static/all.ics 20 5 | tr '\n' ' ')" && sed -i "s#CALENDAR#$upcoming#g" public/index.html
 | 
				
			||||||
 | 
					      - uses: actions/upload-artifact@v3
 | 
				
			||||||
 | 
					        name: Upload pages
 | 
				
			||||||
 | 
					        with:
 | 
				
			||||||
 | 
					          name: enhanced_pages
 | 
				
			||||||
 | 
					          path: public
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  staging:
 | 
				
			||||||
 | 
					    needs: [ calendar ]
 | 
				
			||||||
 | 
					    runs-on: ubuntu-latest
 | 
				
			||||||
 | 
					    environment: staging
 | 
				
			||||||
 | 
					    if: github.ref == 'refs/heads/staging' && github.event_name == 'push'
 | 
				
			||||||
 | 
					    steps:
 | 
				
			||||||
 | 
					      - name: Download pages
 | 
				
			||||||
 | 
					        uses: actions/download-artifact@v3
 | 
				
			||||||
 | 
					        with:
 | 
				
			||||||
 | 
					          name: enhanced_pages
 | 
				
			||||||
 | 
					          path: public
 | 
				
			||||||
 | 
					      - name: Generate timestamp
 | 
				
			||||||
 | 
					        run: echo "timestamp=$(date -u +'%Y-%m-%dT%H%M%SZ')" >> $GITHUB_ENV
 | 
				
			||||||
 | 
					      - name: Create Release Archive
 | 
				
			||||||
 | 
					        uses: thedoctor0/zip-release@0.7.1
 | 
				
			||||||
 | 
					        with:
 | 
				
			||||||
 | 
					          type: zip
 | 
				
			||||||
 | 
					          filename: ../release-staging-${{ env.timestamp }}.zip
 | 
				
			||||||
 | 
					          directory: public
 | 
				
			||||||
 | 
					      - name: Create Release
 | 
				
			||||||
 | 
					        uses: ncipollo/release-action@v1.12.0
 | 
				
			||||||
 | 
					        with:
 | 
				
			||||||
 | 
					          tag: staging-${{ env.timestamp }}
 | 
				
			||||||
 | 
					          name: Website staging version ${{ env.timestamp }}
 | 
				
			||||||
 | 
					          body: Website staging version ${{ env.timestamp }}
 | 
				
			||||||
 | 
					          artifacts: release-staging-${{ env.timestamp }}.zip
 | 
				
			||||||
 | 
					          token: ${{ secrets.GITHUB_TOKEN }}
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  production:
 | 
				
			||||||
 | 
					    needs: [ calendar ]
 | 
				
			||||||
 | 
					    runs-on: ubuntu-latest
 | 
				
			||||||
 | 
					    environment: production
 | 
				
			||||||
 | 
					    if: github.ref == 'refs/heads/production' && github.event_name == 'push'
 | 
				
			||||||
 | 
					    steps:
 | 
				
			||||||
 | 
					      - name: Download pages
 | 
				
			||||||
 | 
					        uses: actions/download-artifact@v3
 | 
				
			||||||
 | 
					        with:
 | 
				
			||||||
 | 
					          name: enhanced_pages
 | 
				
			||||||
 | 
					          path: public
 | 
				
			||||||
 | 
					      - name: Generate timestamp
 | 
				
			||||||
 | 
					        run: echo "timestamp=$(date -u +'%Y-%m-%dT%H%M%SZ')" >> $GITHUB_ENV
 | 
				
			||||||
 | 
					      - name: Create Release Archive
 | 
				
			||||||
 | 
					        uses: thedoctor0/zip-release@0.7.1
 | 
				
			||||||
 | 
					        with:
 | 
				
			||||||
 | 
					          type: zip
 | 
				
			||||||
 | 
					          filename: ../release-production-${{ env.timestamp }}.zip
 | 
				
			||||||
 | 
					          directory: public
 | 
				
			||||||
 | 
					      - name: Create Release
 | 
				
			||||||
 | 
					        uses: ncipollo/release-action@v1.12.0
 | 
				
			||||||
 | 
					        with:
 | 
				
			||||||
 | 
					          makeLatest: true
 | 
				
			||||||
 | 
					          tag: production-${{ env.timestamp }}
 | 
				
			||||||
 | 
					          name: Website production version ${{ env.timestamp }}
 | 
				
			||||||
 | 
					          body: Website production version ${{ env.timestamp }}
 | 
				
			||||||
 | 
					          artifacts: release-production-${{ env.timestamp }}.zip
 | 
				
			||||||
 | 
					          token: ${{ secrets.GITHUB_TOKEN }}
 | 
				
			||||||
							
								
								
									
										94
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										94
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							| 
						 | 
					@ -1,2 +1,94 @@
 | 
				
			||||||
/public
 | 
					 | 
				
			||||||
static/all.ics
 | 
					static/all.ics
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Created by https://www.toptal.com/developers/gitignore/api/windows,linux,macos,hugo
 | 
				
			||||||
 | 
					# Edit at https://www.toptal.com/developers/gitignore?templates=windows,linux,macos,hugo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Hugo ###
 | 
				
			||||||
 | 
					# Generated files by hugo
 | 
				
			||||||
 | 
					/public/
 | 
				
			||||||
 | 
					/resources/_gen/
 | 
				
			||||||
 | 
					/assets/jsconfig.json
 | 
				
			||||||
 | 
					hugo_stats.json
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Executable may be added to repository
 | 
				
			||||||
 | 
					hugo.exe
 | 
				
			||||||
 | 
					hugo.darwin
 | 
				
			||||||
 | 
					hugo.linux
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Temporary lock file while building
 | 
				
			||||||
 | 
					/.hugo_build.lock
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Linux ###
 | 
				
			||||||
 | 
					*~
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# temporary files which can be created if a process still has a handle open of a deleted file
 | 
				
			||||||
 | 
					.fuse_hidden*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# KDE directory preferences
 | 
				
			||||||
 | 
					.directory
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Linux trash folder which might appear on any partition or disk
 | 
				
			||||||
 | 
					.Trash-*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# .nfs files are created when an open file is removed but is still being accessed
 | 
				
			||||||
 | 
					.nfs*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### macOS ###
 | 
				
			||||||
 | 
					# General
 | 
				
			||||||
 | 
					.DS_Store
 | 
				
			||||||
 | 
					.AppleDouble
 | 
				
			||||||
 | 
					.LSOverride
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Icon must end with two \r
 | 
				
			||||||
 | 
					Icon
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Thumbnails
 | 
				
			||||||
 | 
					._*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Files that might appear in the root of a volume
 | 
				
			||||||
 | 
					.DocumentRevisions-V100
 | 
				
			||||||
 | 
					.fseventsd
 | 
				
			||||||
 | 
					.Spotlight-V100
 | 
				
			||||||
 | 
					.TemporaryItems
 | 
				
			||||||
 | 
					.Trashes
 | 
				
			||||||
 | 
					.VolumeIcon.icns
 | 
				
			||||||
 | 
					.com.apple.timemachine.donotpresent
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Directories potentially created on remote AFP share
 | 
				
			||||||
 | 
					.AppleDB
 | 
				
			||||||
 | 
					.AppleDesktop
 | 
				
			||||||
 | 
					Network Trash Folder
 | 
				
			||||||
 | 
					Temporary Items
 | 
				
			||||||
 | 
					.apdisk
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### macOS Patch ###
 | 
				
			||||||
 | 
					# iCloud generated files
 | 
				
			||||||
 | 
					*.icloud
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Windows ###
 | 
				
			||||||
 | 
					# Windows thumbnail cache files
 | 
				
			||||||
 | 
					Thumbs.db
 | 
				
			||||||
 | 
					Thumbs.db:encryptable
 | 
				
			||||||
 | 
					ehthumbs.db
 | 
				
			||||||
 | 
					ehthumbs_vista.db
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Dump file
 | 
				
			||||||
 | 
					*.stackdump
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Folder config file
 | 
				
			||||||
 | 
					[Dd]esktop.ini
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Recycle Bin used on file shares
 | 
				
			||||||
 | 
					$RECYCLE.BIN/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Windows Installer files
 | 
				
			||||||
 | 
					*.cab
 | 
				
			||||||
 | 
					*.msi
 | 
				
			||||||
 | 
					*.msix
 | 
				
			||||||
 | 
					*.msm
 | 
				
			||||||
 | 
					*.msp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Windows shortcuts
 | 
				
			||||||
 | 
					*.lnk
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# End of https://www.toptal.com/developers/gitignore/api/windows,linux,macos,hugo
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,93 +0,0 @@
 | 
				
			||||||
stages:
 | 
					 | 
				
			||||||
  - pages
 | 
					 | 
				
			||||||
  - calendar
 | 
					 | 
				
			||||||
  - deploy
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
cache:
 | 
					 | 
				
			||||||
  paths:
 | 
					 | 
				
			||||||
    - ~/.cache/pip/
 | 
					 | 
				
			||||||
    - public/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
variables:
 | 
					 | 
				
			||||||
  GIT_SUBMODULE_STRATEGY: recursive
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
build_pages:
 | 
					 | 
				
			||||||
  image: "golang:1.10-alpine3.8"
 | 
					 | 
				
			||||||
  stage: pages
 | 
					 | 
				
			||||||
  variables:
 | 
					 | 
				
			||||||
    SHELL: "/bin/sh"
 | 
					 | 
				
			||||||
  artifacts:
 | 
					 | 
				
			||||||
    expire_in: "1 week"
 | 
					 | 
				
			||||||
    untracked: true
 | 
					 | 
				
			||||||
  script:
 | 
					 | 
				
			||||||
    - rm -rf public/*
 | 
					 | 
				
			||||||
    - apk add --no-cache --upgrade hugo
 | 
					 | 
				
			||||||
    - hugo $(cat .hugo-params)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
build_calendar:
 | 
					 | 
				
			||||||
  image: "python:3.11.1-alpine3.17"
 | 
					 | 
				
			||||||
  stage: calendar
 | 
					 | 
				
			||||||
  dependencies: 
 | 
					 | 
				
			||||||
    - build_pages
 | 
					 | 
				
			||||||
  artifacts:
 | 
					 | 
				
			||||||
    expire_in: "1 week"
 | 
					 | 
				
			||||||
    untracked: true
 | 
					 | 
				
			||||||
  variables:
 | 
					 | 
				
			||||||
    SHELL: "/bin/sh"
 | 
					 | 
				
			||||||
  script:
 | 
					 | 
				
			||||||
    - apk --no-cache update
 | 
					 | 
				
			||||||
    - pip install -r requirements.txt
 | 
					 | 
				
			||||||
    - python tools/merge_cals.py
 | 
					 | 
				
			||||||
    - cp static/all.ics public/all.ics
 | 
					 | 
				
			||||||
    - upcoming="$(python tools/gen_upcoming.py static/all.ics 20 5|tr '\n' ' ')" && sed -i "s#CALENDAR#$upcoming#g" public/index.html
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
deploy_staging:
 | 
					 | 
				
			||||||
  image: "alpine:3.17"
 | 
					 | 
				
			||||||
  stage: deploy
 | 
					 | 
				
			||||||
  dependencies: 
 | 
					 | 
				
			||||||
    - build_calendar
 | 
					 | 
				
			||||||
  variables:
 | 
					 | 
				
			||||||
    SHELL: "/bin/sh"
 | 
					 | 
				
			||||||
  script:
 | 
					 | 
				
			||||||
    - apk --no-cache --upgrade add openssh-client rsync
 | 
					 | 
				
			||||||
    - mkdir -p ~/.ssh
 | 
					 | 
				
			||||||
    - eval $(ssh-agent -s)
 | 
					 | 
				
			||||||
    - echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config
 | 
					 | 
				
			||||||
    - echo "$PRIVATE_KEY" | ssh-add -
 | 
					 | 
				
			||||||
    - rsync -e "ssh -l deploy -p 31337" -av --delete public/ 195.160.173.9:staging
 | 
					 | 
				
			||||||
  when: on_success
 | 
					 | 
				
			||||||
  environment:
 | 
					 | 
				
			||||||
    name: staging
 | 
					 | 
				
			||||||
    url: https://staging.berlin.ccc.de/
 | 
					 | 
				
			||||||
  artifacts:
 | 
					 | 
				
			||||||
    expire_in: "1 week"
 | 
					 | 
				
			||||||
    paths:
 | 
					 | 
				
			||||||
      - public/
 | 
					 | 
				
			||||||
  only:
 | 
					 | 
				
			||||||
     - staging
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
deploy_production:
 | 
					 | 
				
			||||||
  image: "alpine:3.17"
 | 
					 | 
				
			||||||
  stage: deploy
 | 
					 | 
				
			||||||
  dependencies: 
 | 
					 | 
				
			||||||
    - build_calendar
 | 
					 | 
				
			||||||
  variables:
 | 
					 | 
				
			||||||
    SHELL: "/bin/sh"
 | 
					 | 
				
			||||||
  script:
 | 
					 | 
				
			||||||
    - apk --no-cache --upgrade add openssh-client rsync
 | 
					 | 
				
			||||||
    - mkdir -p ~/.ssh
 | 
					 | 
				
			||||||
    - eval $(ssh-agent -s)
 | 
					 | 
				
			||||||
    - echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config
 | 
					 | 
				
			||||||
    - echo "$PRIVATE_KEY" | ssh-add -
 | 
					 | 
				
			||||||
    - rsync -e "ssh -l deploy -p 31337" -av --delete public/ 195.160.173.9:production
 | 
					 | 
				
			||||||
  when: on_success
 | 
					 | 
				
			||||||
  environment:
 | 
					 | 
				
			||||||
    name: production
 | 
					 | 
				
			||||||
    url: https://berlin.ccc.de/
 | 
					 | 
				
			||||||
  artifacts:
 | 
					 | 
				
			||||||
    expire_in: "1 week"
 | 
					 | 
				
			||||||
    paths:
 | 
					 | 
				
			||||||
      - public/
 | 
					 | 
				
			||||||
  only:
 | 
					 | 
				
			||||||
     - production
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1 +1 @@
 | 
				
			||||||
-b https://berlin.ccc.de/
 | 
					--baseURL=https://berlin.ccc.de/
 | 
				
			||||||
							
								
								
									
										1
									
								
								.python-version
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								.python-version
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1 @@
 | 
				
			||||||
 | 
					3.11
 | 
				
			||||||
							
								
								
									
										62
									
								
								README.md
									
										
									
									
									
								
							
							
						
						
									
										62
									
								
								README.md
									
										
									
									
									
								
							| 
						 | 
					@ -1,45 +1,51 @@
 | 
				
			||||||
[](https://gitlab.berlin.ccc.de/cccb/www/commits/master)
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# CCCB Website
 | 
					# CCCB Website
 | 
				
			||||||
 | 
					
 | 
				
			||||||
This is the website of CCCB.
 | 
					This is the website of the CCCB.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Getting started
 | 
					## Getting started
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Get Hugo: <https://gohugo.io/getting-started/installing>
 | 
					1. Get Hugo: <https://gohugo.io/getting-started/installing>
 | 
				
			||||||
 | 
					2. Clone this repo
 | 
				
			||||||
Clone this repo
 | 
					   ```shell
 | 
				
			||||||
```
 | 
					   git clone https://github.com/cccb/www
 | 
				
			||||||
git clone https://github.com/cccb/www
 | 
					   ```
 | 
				
			||||||
```
 | 
					3. Switch directory
 | 
				
			||||||
 | 
					   ```shell
 | 
				
			||||||
Switch directory
 | 
					   cd www
 | 
				
			||||||
```
 | 
					   ```
 | 
				
			||||||
cd www
 | 
					3. Fetch Submodules
 | 
				
			||||||
```
 | 
					   ```shell
 | 
				
			||||||
 | 
					   git submodule update --recursive --remote --init
 | 
				
			||||||
Fetch Submodules
 | 
					   ```
 | 
				
			||||||
```
 | 
					 | 
				
			||||||
git submodule update --recursive --remote --init
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Run site locally
 | 
					### Run site locally
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Run hugo webserver
 | 
					Run hugo webserver:
 | 
				
			||||||
```
 | 
					
 | 
				
			||||||
 | 
					```shell
 | 
				
			||||||
hugo serve
 | 
					hugo serve
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
Point your browser to http://localhost:1313/
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
To ready your site for upload, run "./build.sh", which also generates all.ics and adds the calendar table to index.html
 | 
					Point your browser to: http://localhost:1313/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					To ready your site for upload, run `./build.sh`, which also generates `all.ics` and adds the calendar table to `index.html`.
 | 
				
			||||||
Every change you make on the project will be reflected in your browser as long as `hugo serve` is running.
 | 
					Every change you make on the project will be reflected in your browser as long as `hugo serve` is running.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Making a change
 | 
					## Making a change
 | 
				
			||||||
 | 
					
 | 
				
			||||||
* Use your local dev setup (see Getting started) or via GitLab editor. 
 | 
					1. Use your local dev setup (see Getting started) or via GitHub editor.
 | 
				
			||||||
* Make your change in `staging` branch.
 | 
					2. Make your change in `staging` branch.
 | 
				
			||||||
* Commit (and push) your change.
 | 
					3. Commit (and push) your change.
 | 
				
			||||||
* Gitlab CI is running pipeline. If successfull, check [Staging Website](https://staging.berlin.ccc.de/) if change is correct.
 | 
					4. GitHub Actions is running the release workflow.
 | 
				
			||||||
* Create merge request to merge changes from `staging` to `production`. Ask somebody to check merge request or if small change, merge yourself.
 | 
					   - If successful, check [Staging Website](https://staging.berlin.ccc.de/) if change is correct.
 | 
				
			||||||
* Gitlab CI is running pipeline. If successfull, check [Website](https://berlin.ccc.de/) if change is correct.
 | 
					5. Create merge request to merge changes from `staging` to `production` branch. Ask somebody to check merge request or if small change, merge yourself.
 | 
				
			||||||
 | 
					6. GitHub Actions is running the release workflow.
 | 
				
			||||||
 | 
					   - If successfull, check [Website](https://berlin.ccc.de/) if change is correct.
 | 
				
			||||||
 | 
					7. Profit!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					---
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Made with ❤️ and [Hugo](https://gohugo.io).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										13
									
								
								TODO.md
									
										
									
									
									
								
							
							
						
						
									
										13
									
								
								TODO.md
									
										
									
									
									
								
							| 
						 | 
					@ -1,15 +1,15 @@
 | 
				
			||||||
Todo
 | 
					# Todo
 | 
				
			||||||
----
 | 
					
 | 
				
			||||||
- DSGVO-compliant Datenschutzerklärung reinbasteln
 | 
					- DSGVO-compliant Datenschutzerklärung reinbasteln
 | 
				
			||||||
- Entscheiden, welche Seiten sonst noch konvertiert werden sollen und welche in die ewigen Datengründe gehen können
 | 
					- Entscheiden, welche Seiten sonst noch konvertiert werden sollen und welche in die ewigen Datengründe gehen können
 | 
				
			||||||
 | 
					- add nix config to repo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Done
 | 
					# Done
 | 
				
			||||||
----
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
- Template aussuchen
 | 
					- Template aussuchen
 | 
				
			||||||
- Rausfinden, wie man eine Seite konvertiert
 | 
					- Rausfinden, wie man eine Seite konvertiert
 | 
				
			||||||
  - hugo new page/mypage.md
 | 
					  - `hugo new page/mypage.md`
 | 
				
			||||||
  - pandoc -f mediawiki page.mw -t markdown >> page/mypage.md
 | 
					  - `pandoc -f mediawiki page.mw -t markdown >> page/mypage.md`
 | 
				
			||||||
- Wichtigste Seiten konvertieren
 | 
					- Wichtigste Seiten konvertieren
 | 
				
			||||||
- Membership-Seite auf den aktuellen Stand der Wahrheit bringen
 | 
					- Membership-Seite auf den aktuellen Stand der Wahrheit bringen
 | 
				
			||||||
- Ical template bauen
 | 
					- Ical template bauen
 | 
				
			||||||
| 
						 | 
					@ -17,3 +17,4 @@ Done
 | 
				
			||||||
- Bestehende Datengarten-Termine konvertieren
 | 
					- Bestehende Datengarten-Termine konvertieren
 | 
				
			||||||
  - ggf. template mit frontmatter
 | 
					  - ggf. template mit frontmatter
 | 
				
			||||||
- Theme forken, alle assets sollten lokal gehosted sein und nicht von irgendwelchen CDNs bezogen werden (HTTP/2 ftw!)
 | 
					- Theme forken, alle assets sollten lokal gehosted sein und nicht von irgendwelchen CDNs bezogen werden (HTTP/2 ftw!)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										7
									
								
								build.sh
									
										
									
									
									
								
							
							
						
						
									
										7
									
								
								build.sh
									
										
									
									
									
								
							| 
						 | 
					@ -1,7 +1,8 @@
 | 
				
			||||||
#!/usr/bin/env sh
 | 
					#!/bin/sh
 | 
				
			||||||
 | 
					
 | 
				
			||||||
hugo $(cat .hugo-params)
 | 
					hugo $(cat .hugo-params)
 | 
				
			||||||
tools/merge_cals.py
 | 
					./tools/merge_cals.py
 | 
				
			||||||
upcoming="$(tools/gen_upcoming.py static/all.ics 20 5|tr '\n' ' ')"
 | 
					upcoming="$(tools/gen_upcoming.py static/all.ics 20 5 | tr '\n' ' ')"
 | 
				
			||||||
cp static/all.ics public/all.ics
 | 
					cp static/all.ics public/all.ics
 | 
				
			||||||
sed -i "s#CALENDAR#$upcoming#g" public/index.html
 | 
					sed -i "s#CALENDAR#$upcoming#g" public/index.html
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -16,6 +16,8 @@ Params:
 | 
				
			||||||
  readingTime: true
 | 
					  readingTime: true
 | 
				
			||||||
  useHLJS: true
 | 
					  useHLJS: true
 | 
				
			||||||
  DateForm: "30.12.2006"
 | 
					  DateForm: "30.12.2006"
 | 
				
			||||||
 | 
					  # for GDPR / EU-DSGVO compliance
 | 
				
			||||||
 | 
					  selfHosted: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
taxonomies:
 | 
					taxonomies:
 | 
				
			||||||
  category: "categories"
 | 
					  category: "categories"
 | 
				
			||||||
| 
						 | 
					@ -63,7 +65,6 @@ mediaTypes:
 | 
				
			||||||
    suffixes:
 | 
					    suffixes:
 | 
				
			||||||
    - "xml"
 | 
					    - "xml"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
outputFormats:
 | 
					outputFormats:
 | 
				
			||||||
  RSS:
 | 
					  RSS:
 | 
				
			||||||
    mediaType: "application/rss"
 | 
					    mediaType: "application/rss"
 | 
				
			||||||
| 
						 | 
					@ -80,3 +81,4 @@ outputs:
 | 
				
			||||||
  page:
 | 
					  page:
 | 
				
			||||||
  - "HTML"
 | 
					  - "HTML"
 | 
				
			||||||
  - "Calendar"
 | 
					  - "Calendar"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,7 +11,7 @@
 | 
				
			||||||
            {{ range .Params.tags }}
 | 
					            {{ range .Params.tags }}
 | 
				
			||||||
              <a href="{{ $.Site.LanguagePrefix | absURL }}/tags/{{ . | urlize }}/">{{ . }}</a> 
 | 
					              <a href="{{ $.Site.LanguagePrefix | absURL }}/tags/{{ . | urlize }}/">{{ . }}</a> 
 | 
				
			||||||
            {{ end }}
 | 
					            {{ end }}
 | 
				
			||||||
          </div>
 | 
					          </div><!--/.blog-tags-->
 | 
				
			||||||
        {{ end }}
 | 
					        {{ end }}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        {{ if .Site.Params.socialShare }}
 | 
					        {{ if .Site.Params.socialShare }}
 | 
				
			||||||
| 
						 | 
					@ -19,24 +19,24 @@
 | 
				
			||||||
            <section id="social-share">
 | 
					            <section id="social-share">
 | 
				
			||||||
              <ul class="list-inline footer-links">
 | 
					              <ul class="list-inline footer-links">
 | 
				
			||||||
                {{ partial "share-links" . }}
 | 
					                {{ partial "share-links" . }}
 | 
				
			||||||
              </ul>
 | 
					              </ul><!--/.social-share-->
 | 
				
			||||||
            </section>
 | 
					            </section><!--/.list-inline .footer-links-->
 | 
				
			||||||
        {{ end }}
 | 
					        {{ end }}
 | 
				
			||||||
      </article>
 | 
					      </article><!--/.blog-post-->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      {{ if ne .Type "page" }}
 | 
					      {{ if ne .Type "page" }}
 | 
				
			||||||
        <ul class="pager blog-pager">
 | 
					        <ul class="pager blog-pager">
 | 
				
			||||||
          {{ if .PrevInSection }}
 | 
					          {{ if .PrevInSection }}
 | 
				
			||||||
            <li class="previous">
 | 
					            <li class="previous">
 | 
				
			||||||
              <a href="{{ .PrevInSection.Permalink }}" data-toggle="tooltip" data-placement="top" title="{{ .PrevInSection.Title }}">← {{ i18n "previousPost" }}</a>
 | 
					              <a href="{{ .PrevInSection.Permalink }}" data-toggle="tooltip" data-placement="top" title="{{ .PrevInSection.Title }}">← {{ i18n "previousPost" }}</a>
 | 
				
			||||||
            </li>
 | 
					            </li><!--/.previous-->
 | 
				
			||||||
          {{ end }}
 | 
					          {{ end }}
 | 
				
			||||||
          {{ if .NextInSection }}
 | 
					          {{ if .NextInSection }}
 | 
				
			||||||
            <li class="next">
 | 
					            <li class="next">
 | 
				
			||||||
              <a href="{{ .NextInSection.Permalink }}" data-toggle="tooltip" data-placement="top" title="{{ .NextInSection.Title }}">{{ i18n "nextPost" }} →</a>
 | 
					              <a href="{{ .NextInSection.Permalink }}" data-toggle="tooltip" data-placement="top" title="{{ .NextInSection.Title }}">{{ i18n "nextPost" }} →</a>
 | 
				
			||||||
            </li>
 | 
					            </li><!--/.next-->
 | 
				
			||||||
          {{ end }}
 | 
					          {{ end }}
 | 
				
			||||||
        </ul>
 | 
					        </ul><!--/.pager .blog-pager-->
 | 
				
			||||||
      {{ end }}
 | 
					      {{ end }}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -44,16 +44,16 @@
 | 
				
			||||||
        {{ if .Site.DisqusShortname }}
 | 
					        {{ if .Site.DisqusShortname }}
 | 
				
			||||||
          <div class="disqus-comments">
 | 
					          <div class="disqus-comments">
 | 
				
			||||||
            {{ template "_internal/disqus.html" . }}
 | 
					            {{ template "_internal/disqus.html" . }}
 | 
				
			||||||
          </div>
 | 
					          </div><!--/.disqus-comments-->
 | 
				
			||||||
        {{ end }}
 | 
					        {{ end }}
 | 
				
			||||||
        {{ if .Site.Params.staticman }}
 | 
					        {{ if .Site.Params.staticman }}
 | 
				
			||||||
          <div class="staticman-comments">
 | 
					          <div class="staticman-comments">
 | 
				
			||||||
            {{ partial "staticman-comments.html" . }}
 | 
					            {{ partial "staticman-comments.html" . }}
 | 
				
			||||||
          </div>
 | 
					          </div><!--/.staticman-comments-->
 | 
				
			||||||
        {{ end }}
 | 
					        {{ end }}
 | 
				
			||||||
      {{ end }}
 | 
					      {{ end }}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    </div>
 | 
					    </div><!--/.col-lg-8 .col-lg-offset-2 .col-md-10 .col-md-offset-1-->
 | 
				
			||||||
  </div>
 | 
					  </div><!--/.row-->
 | 
				
			||||||
</div>
 | 
					</div><!--/.container-->
 | 
				
			||||||
{{ end }}
 | 
					{{ end }}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,12 +1,12 @@
 | 
				
			||||||
{{ $series := or (.Get 0) $.Page.Params.series }}
 | 
					{{ $series := or (.Get 0) $.Page.Params.series }}
 | 
				
			||||||
<table>
 | 
					<table>
 | 
				
			||||||
<tr>
 | 
					  <tr>
 | 
				
			||||||
<th>No.</th>
 | 
					    <th>No.</th>
 | 
				
			||||||
<th>Date</th>
 | 
					    <th>Date</th>
 | 
				
			||||||
<th>Speaker</th>
 | 
					    <th>Speaker</th>
 | 
				
			||||||
<th>Topic</th>
 | 
					    <th>Topic</th>
 | 
				
			||||||
<th>Video</th>
 | 
					    <th>Video</th>
 | 
				
			||||||
</tr>
 | 
					  </tr>
 | 
				
			||||||
  {{ range $ind,$art := $.Site.Pages.ByDate.Reverse }}
 | 
					  {{ range $ind,$art := $.Site.Pages.ByDate.Reverse }}
 | 
				
			||||||
    {{ if eq $art.Params.series $series }}
 | 
					    {{ if eq $art.Params.series $series }}
 | 
				
			||||||
  <tr>
 | 
					  <tr>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1 +1 @@
 | 
				
			||||||
icalendar
 | 
					icalendar==5.0.7
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
										
											Binary file not shown.
										
									
								
							| 
		 Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 41 KiB  | 
										
											Binary file not shown.
										
									
								
							| 
		 Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 22 KiB  | 
| 
						 | 
					@ -1 +1 @@
 | 
				
			||||||
Subproject commit 0da13d20d0bf3c9002651f06a54d21608d292958
 | 
					Subproject commit 1e66e4ae945f12da3f8e6fb603c396156c1b04e9
 | 
				
			||||||
| 
						 | 
					@ -1,15 +0,0 @@
 | 
				
			||||||
#!/bin/bash
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if [ $# -lt 2 ]; then
 | 
					 | 
				
			||||||
  echo "Usage: $0 Mediawiki_Page_Name [page|post]"
 | 
					 | 
				
			||||||
  exit
 | 
					 | 
				
			||||||
fi
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
echo Converting $1...
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
page=$(echo $1 | sed 's,/,_,g'|tr '[:upper:]' '[:lower:]')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
hugo new $2/$page.md
 | 
					 | 
				
			||||||
curl -s  https://berlin.ccc.de/api.php\?action\=query\&prop\=revisions\&rvprop\=content\&format\=json\&titles\=$1 | \
 | 
					 | 
				
			||||||
	 jq -r '.query.pages |..| objects|.["*"]'| sed '/null/d' | pandoc -f mediawiki -t markdown  \
 | 
					 | 
				
			||||||
	>> content/$2/$page.md
 | 
					 | 
				
			||||||
							
								
								
									
										17
									
								
								tools/convert_page.sh
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										17
									
								
								tools/convert_page.sh
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
					@ -0,0 +1,17 @@
 | 
				
			||||||
 | 
					#!/bin/sh
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if [ $# -lt 2 ]; then
 | 
				
			||||||
 | 
					  echo "Usage: $0 Mediawiki_Page_Name [page|post]"
 | 
				
			||||||
 | 
					  exit
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					echo Converting $1...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					page=$(echo $1 | sed 's,/,_,g' | tr '[:upper:]' '[:lower:]')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					hugo new $2/$page.md
 | 
				
			||||||
 | 
					curl -s "https://berlin.ccc.de/api.php?action=query&prop=revisions&rvprop=content&format=json&titles=$1" \
 | 
				
			||||||
 | 
					    | jq -r '.query.pages |..| objects|.["*"]' \
 | 
				
			||||||
 | 
					    | sed '/null/d' \
 | 
				
			||||||
 | 
					    | pandoc -f mediawiki -t markdown \
 | 
				
			||||||
 | 
					    >> content/$2/$page.md
 | 
				
			||||||
| 
						 | 
					@ -3,7 +3,6 @@
 | 
				
			||||||
import sys
 | 
					import sys
 | 
				
			||||||
import logging
 | 
					import logging
 | 
				
			||||||
import locale
 | 
					import locale
 | 
				
			||||||
from pprint import pprint
 | 
					 | 
				
			||||||
from dateutil.parser import parse
 | 
					from dateutil.parser import parse
 | 
				
			||||||
from datetime import datetime, timedelta
 | 
					from datetime import datetime, timedelta
 | 
				
			||||||
from dateutil.rrule import rruleset, rrulestr
 | 
					from dateutil.rrule import rruleset, rrulestr
 | 
				
			||||||
| 
						 | 
					@ -13,78 +12,82 @@ import icalendar
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def vevent_to_event(event, rrstart=None):
 | 
					def vevent_to_event(event, rrstart=None):
 | 
				
			||||||
    if rrstart == None:
 | 
					    if rrstart == None:
 | 
				
			||||||
		begin = parse(event['DTSTART'].to_ical())
 | 
					        begin = parse(event["DTSTART"].to_ical())
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
        begin = rrstart
 | 
					        begin = rrstart
 | 
				
			||||||
	return { "name": event['SUMMARY'].to_ical(), "url": event['URL'].to_ical(), "begin": begin }
 | 
					
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					        "name": event["SUMMARY"].to_ical(),
 | 
				
			||||||
 | 
					        "url": event["URL"].to_ical(),
 | 
				
			||||||
 | 
					        "begin": begin
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def parse_single_event(event, start, end):
 | 
					def parse_single_event(event, start, end):
 | 
				
			||||||
	logging.info("Processing single event %s" % event['SUMMARY'].to_ical().decode('utf-8'))
 | 
					    logging.info(f"Processing single event {event['SUMMARY'].to_ical().decode('utf-8')}")
 | 
				
			||||||
	dtstart = parse(event['DTSTART'].to_ical())
 | 
					    dtstart = parse(event["DTSTART"].to_ical())
 | 
				
			||||||
    if dtstart >= start and dtstart < end:
 | 
					    if dtstart >= start and dtstart < end:
 | 
				
			||||||
        return vevent_to_event(event)
 | 
					        return vevent_to_event(event)
 | 
				
			||||||
	else:
 | 
					 | 
				
			||||||
		return None
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def parse_recurring_event(event, start, end):
 | 
					def parse_recurring_event(event, start, end):
 | 
				
			||||||
	logging.info("Processing recurring event %s" % event['SUMMARY'].to_ical().decode('utf-8'))
 | 
					    logging.info(f"Processing recurring event {event['SUMMARY'].to_ical().decode('utf-8')}")
 | 
				
			||||||
	dtstart = parse(event['DTSTART'].to_ical())
 | 
					    dtstart = parse(event["DTSTART"].to_ical())
 | 
				
			||||||
    rs = rruleset()
 | 
					    rs = rruleset()
 | 
				
			||||||
	rs.rrule(rrulestr(event['RRULE'].to_ical().decode('utf-8'), dtstart=dtstart))
 | 
					    rs.rrule(rrulestr(event["RRULE"].to_ical().decode("utf-8"), dtstart=dtstart))
 | 
				
			||||||
	if 'EXDATE' in event.keys():
 | 
					    if "EXDATE" in event.keys():
 | 
				
			||||||
		exdates = event['EXDATE']
 | 
					        for exdate in event["EXDATE"]:
 | 
				
			||||||
		for exdate in exdates:
 | 
					 | 
				
			||||||
            rs.exdate(parse(exdate.to_ical()))
 | 
					            rs.exdate(parse(exdate.to_ical()))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dates = list(rs)
 | 
					 | 
				
			||||||
    events = []
 | 
					    events = []
 | 
				
			||||||
	for date in dates:
 | 
					    for date in list(rs):
 | 
				
			||||||
        if date >= start and date < end:
 | 
					        if date >= start and date < end:
 | 
				
			||||||
            events.append(vevent_to_event(event, date))
 | 
					            events.append(vevent_to_event(event, date))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return events
 | 
					    return events
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def find_events(icsfilestr, start, end, num):
 | 
					def find_events(icsfilestr, start, end, num):
 | 
				
			||||||
	with open(icsfilestr, 'r') as icsfile:
 | 
					    with open(icsfilestr, "r") as icsfile:
 | 
				
			||||||
		cal=icalendar.Calendar.from_ical(icsfile.read())
 | 
					        cal = icalendar.Calendar.from_ical(icsfile.read())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	events=[]
 | 
					    events = []
 | 
				
			||||||
    for event in cal.subcomponents:
 | 
					    for event in cal.subcomponents:
 | 
				
			||||||
		if event.name == 'VEVENT':
 | 
					        if event.name == "VEVENT":
 | 
				
			||||||
			if 'RRULE' in event.keys():
 | 
					            if "RRULE" in event.keys():
 | 
				
			||||||
				events = events + parse_recurring_event(event, start, end)
 | 
					                events.extend(parse_recurring_event(event, start, end))
 | 
				
			||||||
			else:
 | 
					            elif ev := parse_single_event(event, start, end) != None:
 | 
				
			||||||
				ev = parse_single_event(event, start, end)
 | 
					 | 
				
			||||||
				if ev != None:
 | 
					 | 
				
			||||||
                events.append(ev)
 | 
					                events.append(ev)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	events = sorted(events, key=lambda k: k['begin'])
 | 
					    events = sorted(events, key=lambda k: k["begin"])
 | 
				
			||||||
    events = events[0:num]
 | 
					    events = events[0:num]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return events
 | 
					    return events
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def format_events(events):
 | 
					def format_events(events):
 | 
				
			||||||
	print('<table class="table table-condensed">')
 | 
					    print("<table class=\"table table-condensed\">")
 | 
				
			||||||
    for event in events:
 | 
					    for event in events:
 | 
				
			||||||
		dateStr = event['begin'].strftime("%A, %d.%m um %H:%M Uhr")
 | 
					        print(
 | 
				
			||||||
		#print("<li><a href=\"%s\">%s: %s</a></li>" % (event['url'].decode('utf-8'), dateStr, event['name'].decode('utf-8')))
 | 
					            "<tr>"
 | 
				
			||||||
		print("<tr><td>%s</td><td><a href=\"%s\">%s</a></td></tr>"
 | 
					            f"<td>{event['begin'].strftime('%A, %d.%m um %H:%M Uhr')}</td>"
 | 
				
			||||||
			% (dateStr, event['url'].decode('utf-8'), event['name'].decode('utf-8')))
 | 
					            f"<td><a href=\"{event['url'].decode('utf-8')}\">{event['name'].decode('utf-8')}</a></td>"
 | 
				
			||||||
	print('</table>')
 | 
					            "</tr>"
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    print("</table><!--/.table .table-condensed-->")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if __name__ == "__main__":
 | 
					if __name__ == "__main__":
 | 
				
			||||||
    if len(sys.argv) < 3:
 | 
					    if len(sys.argv) < 3:
 | 
				
			||||||
		print("Usage: %s calendar max_days max_items" % sys.argv[0])
 | 
					        print(f"Usage: {sys.argv[0]} calendar max_days max_items")
 | 
				
			||||||
        sys.exit(-1)
 | 
					        sys.exit(-1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    locale.setlocale(locale.LC_TIME, "de_DE.UTF-8")
 | 
					    locale.setlocale(locale.LC_TIME, "de_DE.UTF-8")
 | 
				
			||||||
	calendar=sys.argv[1]
 | 
					    calendar = sys.argv[1]
 | 
				
			||||||
	max_days=int(sys.argv[2])
 | 
					    max_days = int(sys.argv[2])
 | 
				
			||||||
	max_items=int(sys.argv[3])
 | 
					    max_items = int(sys.argv[3])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	events=find_events(calendar, datetime.now(), datetime.now() + timedelta(days=max_days), max_items)
 | 
					    now = datetime.now()
 | 
				
			||||||
 | 
					    events = find_events(calendar, now, now + timedelta(days=max_days), max_items)
 | 
				
			||||||
    format_events(events)
 | 
					    format_events(events)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,22 +6,22 @@ import pytz
 | 
				
			||||||
import icalendar
 | 
					import icalendar
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
cals = []
 | 
					calendars = []
 | 
				
			||||||
merged = icalendar.Calendar()
 | 
					merged = icalendar.Calendar()
 | 
				
			||||||
merged.add('prodid', '-//CCCB Calendar Generator//berlin.ccc.de//')
 | 
					merged.add("prodid", "-//CCCB Calendar Generator//berlin.ccc.de//")
 | 
				
			||||||
merged.add('version', '2.0')
 | 
					merged.add("version", "2.0")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
for icsfilestr in glob('public/*/**/*.ics', recursive=True):
 | 
					for icsfilestr in glob("public/*/**/*.ics", recursive=True):
 | 
				
			||||||
	with open(icsfilestr, 'r') as icsfile:
 | 
						with open(icsfilestr, "r") as icsfile:
 | 
				
			||||||
		print('Importing', icsfilestr)
 | 
							print(f"Importing {icsfilestr}")
 | 
				
			||||||
		cals.append(icalendar.Calendar.from_ical(icsfile.read()))
 | 
							calendars.append(icalendar.Calendar.from_ical(icsfile.read()))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
for cal in cals:
 | 
					for calendar in calendars:
 | 
				
			||||||
	for e in cal.subcomponents:
 | 
						for event in calendar.subcomponents:
 | 
				
			||||||
		merged.add_component(e)
 | 
							merged.add_component(event)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
outfile = 'static/all.ics'
 | 
					outfile = "static/all.ics"
 | 
				
			||||||
with open(outfile, 'wb') as f:
 | 
					with open(outfile, "wb") as f:
 | 
				
			||||||
	print(f'writing to {outfile}...')
 | 
						print(f"writing to {outfile}...")
 | 
				
			||||||
	f.write(merged.to_ical())
 | 
						f.write(merged.to_ical())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue