15 Commits
1.2.5 ... 1.2.8

Author SHA1 Message Date
6394a7c880 fix secrets (1st try)
All checks were successful
continuous-integration/drone the build was successful
2021-10-16 15:48:34 +02:00
5ab5e850bd execute the docker build/deploy image with privileged: true
Some checks failed
continuous-integration/drone the build failed
2021-10-16 15:21:01 +02:00
a97a464a83 Merge pull request 'use techknowlogick's drone-docker image' (#20) from fix/docker-build into master
Some checks failed
continuous-integration/drone the build failed
Reviewed-on: #20
2021-10-16 14:39:38 +02:00
2b06efeece use techknowlogick's drone-docker image
All checks were successful
continuous-integration/drone the build was successful
this should fix the docker build issues
2021-10-16 14:35:37 +02:00
024f2b04ce „README.md“ ändern
All checks were successful
continuous-integration/drone the build was successful
2021-10-13 20:09:46 +02:00
bf71d62dc5 version 1.2.8
Some checks failed
continuous-integration/drone the build failed
2021-10-13 20:03:14 +02:00
7dce2c6cfd Merge pull request 'updated mensa URL' (#16) from fix/mensa_url into master
All checks were successful
continuous-integration/drone the build was successful
Reviewed-on: #16
2021-10-13 19:49:53 +02:00
a1dc5656b8 updated mensa URL, thanks to Hannes B.
All checks were successful
continuous-integration/drone the build was successful
2021-10-13 19:47:38 +02:00
dd4c5259d2 Merge pull request 'move ci config from drone to woodpecker' (#18) from fix/ci into master
Some checks failed
continuous-integration/drone the build failed
Reviewed-on: #18
2021-10-13 19:45:32 +02:00
884aab08ed move ci config from drone to woodpecker
Some checks failed
continuous-integration/drone the build failed
2021-10-13 19:39:37 +02:00
c64c8779e3 update kotlin to 1.4
All checks were successful
continuous-integration/drone/push Build is passing
* update spring boot 2.3.2 -> 2.3.3
* update gradle wrapper to version 6.6.1
2020-09-16 18:56:24 +02:00
1d614a06c4 version 1.2.7
All checks were successful
continuous-integration/drone/tag Build is passing
continuous-integration/drone/push Build is passing
* update coroutines 1.3.7 -> 1.3.8
2020-08-16 20:03:37 +02:00
3f10c8afaa fix courseList sorting
All checks were successful
continuous-integration/drone/push Build is passing
closes #15
2020-08-16 19:56:13 +02:00
9de1e295dd fix reading file from resources
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
2020-08-06 17:27:49 +02:00
6287d4582d update spring-boot
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
* add TEST_A and TEST_B courses for testing during summer break
2020-08-06 16:31:05 +02:00
12 changed files with 1791 additions and 57 deletions

View File

@ -1,30 +0,0 @@
kind: pipeline
name: default
steps:
- name: test
image: gradle:jdk11
commands:
- gradle test
- name: build
image: gradle:jdk11
commands:
- gradle bootJar
when:
event:
- tag
- name: docker
image: plugins/docker
settings:
username:
from_secret: docker_username
password:
from_secret: docker_password
repo: mosadxyz/tcor
tags:
- latest
when:
event:
- tag

21
.woodpecker.yml Normal file
View File

@ -0,0 +1,21 @@
pipeline:
test:
image: gradle:jdk11
commands:
- gradle test
build:
image: gradle:jdk11
commands:
- gradle bootJar
when:
event:
- tag
docker:
image: techknowlogick/drone-docker
privileged: true
repo: mosadxyz/tcor
secrets: [docker_username, docker_password]
tags: latest
when:
event:
- tag

View File

@ -1,5 +1,5 @@
![Website](https://img.shields.io/website?down_color=red&down_message=offline&label=tcor.mosad.xyz&up_color=brightgreen&up_message=online&url=https%3A%2F%2Ftcor.mosad.xyz%2Fhealth) ![Website](https://img.shields.io/website?down_color=red&down_message=offline&label=tcor.mosad.xyz&up_color=brightgreen&up_message=online&url=https%3A%2F%2Ftcor.mosad.xyz%2Fhealth)
[![Build Status](https://drone.mosad.xyz/api/badges/Seil0/TheCitadelofRicks/status.svg)](https://drone.mosad.xyz/Seil0/TheCitadelofRicks) [![Build Status](https://ci.mosad.xyz/api/badges/Seil0/TheCitadelofRicks/status.svg)](https://ci.mosad.xyz/Seil0/TheCitadelofRicks)
[![Release](https://img.shields.io/badge/dynamic/json.svg?label=release&url=https://git.mosad.xyz/api/v1/repos/Seil0/TheCitadelofRicks/releases&query=$[0].tag_name)](https://git.mosad.xyz/Seil0/TheCitadelofRicks/releases) [![Release](https://img.shields.io/badge/dynamic/json.svg?label=release&url=https://git.mosad.xyz/api/v1/repos/Seil0/TheCitadelofRicks/releases&query=$[0].tag_name)](https://git.mosad.xyz/Seil0/TheCitadelofRicks/releases)
[![License: GPL v3](https://img.shields.io/badge/License-GPL%20v3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0) [![License: GPL v3](https://img.shields.io/badge/License-GPL%20v3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
# TheCitadelofRicks # TheCitadelofRicks

View File

@ -1,12 +1,12 @@
plugins { plugins {
id 'org.jetbrains.kotlin.jvm' version '1.3.72' id 'org.jetbrains.kotlin.jvm' version '1.4.10'
id 'org.jetbrains.kotlin.plugin.spring' version '1.3.72' id 'org.jetbrains.kotlin.plugin.spring' version '1.4.10'
id 'org.springframework.boot' version '2.3.0.RELEASE' id 'org.springframework.boot' version '2.3.3.RELEASE'
id 'io.spring.dependency-management' version '1.0.9.RELEASE' id 'io.spring.dependency-management' version '1.0.9.RELEASE'
} }
group 'org.mosad' group 'org.mosad'
version '1.2.5' version '1.2.8'
repositories { repositories {
jcenter() jcenter()
@ -15,7 +15,7 @@ repositories {
dependencies { dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.jetbrains.kotlin:kotlin-stdlib' implementation 'org.jetbrains.kotlin:kotlin-stdlib'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7' implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.8'
implementation 'org.jsoup:jsoup:1.13.1' implementation 'org.jsoup:jsoup:1.13.1'
implementation 'com.google.code.gson:gson:2.8.6' implementation 'com.google.code.gson:gson:2.8.6'

View File

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-bin.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

View File

@ -49,7 +49,7 @@ class APIController {
companion object { companion object {
const val apiVersion = "1.2.0" const val apiVersion = "1.2.0"
const val softwareVersion = "1.2.5" const val softwareVersion = "1.2.8"
val startTime = System.currentTimeMillis() / 1000 val startTime = System.currentTimeMillis() / 1000
} }

View File

@ -31,7 +31,7 @@ data class Course(val courseName: String, val courseLink: String)
data class CoursesMeta(val updateTime: Long = 0, val totalCourses: Int = 0) data class CoursesMeta(val updateTime: Long = 0, val totalCourses: Int = 0)
data class CoursesList(val meta: CoursesMeta = CoursesMeta(), val courses: HashMap<String, Course> = HashMap()) data class CoursesList(val meta: CoursesMeta = CoursesMeta(), val courses: SortedMap<String, Course>)
data class CoursesListRet(val meta: CoursesMeta = CoursesMeta(), val courses: ArrayList<Course> = ArrayList()) data class CoursesListRet(val meta: CoursesMeta = CoursesMeta(), val courses: ArrayList<Course> = ArrayList())
// data classes for the Mensa part // data classes for the Mensa part

View File

@ -24,15 +24,14 @@ package org.mosad.thecitadelofricks.controller
import com.google.gson.Gson import com.google.gson.Gson
import kotlinx.coroutines.* import kotlinx.coroutines.*
import org.jsoup.Jsoup
import org.mosad.thecitadelofricks.* import org.mosad.thecitadelofricks.*
import org.mosad.thecitadelofricks.hsoparser.CourseListParser import org.mosad.thecitadelofricks.hsoparser.CourseListParser
import org.mosad.thecitadelofricks.hsoparser.MensaParser import org.mosad.thecitadelofricks.hsoparser.MensaParser
import org.mosad.thecitadelofricks.hsoparser.TimetableParser import org.mosad.thecitadelofricks.hsoparser.TimetableParser
import org.slf4j.Logger import org.slf4j.Logger
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import java.io.BufferedWriter import java.io.*
import java.io.File
import java.io.FileWriter
import java.util.* import java.util.*
import java.util.concurrent.Executors import java.util.concurrent.Executors
import kotlin.collections.ArrayList import kotlin.collections.ArrayList
@ -50,7 +49,7 @@ class CacheController {
companion object{ companion object{
private val logger: Logger = LoggerFactory.getLogger(CacheController::class.java) private val logger: Logger = LoggerFactory.getLogger(CacheController::class.java)
var courseList = CoursesList() var courseList = CoursesList(CoursesMeta(), sortedMapOf())
var mensaMenu = MensaMenu(MensaMeta(0,""), MensaWeek(), MensaWeek()) var mensaMenu = MensaMenu(MensaMeta(0,""), MensaWeek(), MensaWeek())
var timetableList = HashMap<String, TimetableCourseWeek>() // this list contains all timetables var timetableList = HashMap<String, TimetableCourseWeek>() // this list contains all timetables
@ -61,6 +60,20 @@ class CacheController {
* @return timetable of the course (Type: [TimetableCourseWeek]) * @return timetable of the course (Type: [TimetableCourseWeek])
*/ */
fun getTimetable(courseName: String, weekIndex: Int): TimetableCourseWeek = runBlocking { fun getTimetable(courseName: String, weekIndex: Int): TimetableCourseWeek = runBlocking {
// TODO just for testing
if (courseName == "TEST_A" || courseName == "TEST_B") {
val currentTime = System.currentTimeMillis() / 1000
val timetableLink = "https://mosad.xyz"
val weekNumberYear = 0
val instr = javaClass.getResourceAsStream("/html/Timetable_normal-week.html")
val htmlDoc = Jsoup.parse(instr,"UTF-8", "https://www.hs-offenburg.de/")
val timetableTest = TimetableParser().parseTimeTable(htmlDoc)
return@runBlocking TimetableCourseWeek(TimetableCourseMeta(currentTime, courseName, weekIndex, weekNumberYear, timetableLink), timetableTest)
}
return@runBlocking timetableList.getOrPut("$courseName-$weekIndex") { return@runBlocking timetableList.getOrPut("$courseName-$weekIndex") {
val timetableLink = courseList.courses[courseName] val timetableLink = courseList.courses[courseName]
?.courseLink ?.courseLink
@ -124,9 +137,13 @@ class CacheController {
*/ */
private fun asyncUpdateCourseList() = GlobalScope.launch { private fun asyncUpdateCourseList() = GlobalScope.launch {
CourseListParser().getCourseLinks(StartupController.courseListURL)?.let { CourseListParser().getCourseLinks(StartupController.courseListURL)?.let {
courseList = CoursesList(CoursesMeta(System.currentTimeMillis() / 1000, it.size), it) courseList = CoursesList(CoursesMeta(System.currentTimeMillis() / 1000, it.size), it.toSortedMap())
} }
// TODO just for testing
courseList.courses["TEST_A"] = Course("TEST_A", "https://mosad.xyz")
courseList.courses["TEST_B"] = Course("TEST_B", "https://mosad.xyz")
logger.info("Updated courses successful at ${Date(courseList.meta.updateTime * 1000)}") logger.info("Updated courses successful at ${Date(courseList.meta.updateTime * 1000)}")
} }

View File

@ -44,7 +44,7 @@ class StartupController {
var cachetAPIKey = "0" var cachetAPIKey = "0"
var cachetBaseURL = "https://status.mosad.xyz" var cachetBaseURL = "https://status.mosad.xyz"
var courseListURL = "https://www.hs-offenburg.de/studium/vorlesungsplaene/" var courseListURL = "https://www.hs-offenburg.de/studium/vorlesungsplaene/"
var mensaMenuURL = "https://www.swfr.de/de/essen-trinken/speiseplaene/mensa-offenburg/" var mensaMenuURL = "https://www.swfr.de/essen-trinken/speiseplaene/mensa-offenburg/"
var mensaName = "Offenburg" var mensaName = "Offenburg"
} }
@ -92,7 +92,7 @@ class StartupController {
mensaMenuURL = try { mensaMenuURL = try {
properties.getProperty("mensaMenuURL") properties.getProperty("mensaMenuURL")
} catch (ex: Exception) { } catch (ex: Exception) {
"https://www.swfr.de/de/essen-trinken/speiseplaene/mensa-offenburg/" "https://www.swfr.de/essen-trinken/speiseplaene/mensa-offenburg/"
} }
mensaName = try { mensaName = try {
@ -113,7 +113,7 @@ class StartupController {
properties.setProperty("cachetAPIKey", "0") properties.setProperty("cachetAPIKey", "0")
properties.setProperty("cachetBaseURL", "https://status.mosad.xyz") properties.setProperty("cachetBaseURL", "https://status.mosad.xyz")
properties.setProperty("mensaMenuURL", "https://www.swfr.de/de/essen-trinken/speiseplaene/mensa-offenburg/") properties.setProperty("mensaMenuURL", "https://www.swfr.de/essen-trinken/speiseplaene/mensa-offenburg/")
properties.setProperty("mensaName", "Offenburg") properties.setProperty("mensaName", "Offenburg")
val outputStream = FileOutputStream(fileConfig) val outputStream = FileOutputStream(fileConfig)
@ -145,4 +145,4 @@ class StartupController {
} }
} }
} }
} }

File diff suppressed because one or more lines are too long

View File

@ -28,7 +28,7 @@ import org.junit.jupiter.api.Test
import java.io.File import java.io.File
internal class MensaParserTest { internal class MensaParserTest {
private val mensaMenuURL = "https://www.swfr.de/de/essen-trinken/speiseplaene/mensa-offenburg/" private val mensaMenuURL = "https://www.swfr.de/essen-trinken/speiseplaene/mensa-offenburg/"
@Test @Test
fun parseMensaMenuNormalWeek() { fun parseMensaMenuNormalWeek() {
@ -57,4 +57,4 @@ internal class MensaParserTest {
val urlNextWeek = MensaParser().getMenuLinkNextWeek(mensaMenuURL) // this need a connection to the swfr server val urlNextWeek = MensaParser().getMenuLinkNextWeek(mensaMenuURL) // this need a connection to the swfr server
Assertions.assertNotNull(urlNextWeek) Assertions.assertNotNull(urlNextWeek)
} }
} }

View File

@ -1,7 +1,7 @@
<div id="speiseplan-tabs"> <div id="speiseplan-tabs">
<div id="tab-menu-container" class="row"> <div id="tab-menu-container" class="row">
<div class="col-md-1 col-xs-6"> <div class="col-md-1 col-xs-6">
<a class="prev-week" title="eine Woche zurück" href="/de/essen-trinken/speiseplaene/mensa-offenburg/?tx_swfrspeiseplan_pi1%5BweekToShow%5D=0&amp;tx_swfrspeiseplan_pi1%5Baction%5D=show&amp;tx_swfrspeiseplan_pi1%5Bcontroller%5D=Speiseplan&amp;cHash=ad074b11cc01a680e4c0d0675dd1f91c"><img src="/fileadmin/templates/images/keil-grau-links.png" width="16" height="16" alt="" /><span class="d-inline d-sm-none">vorherige Woche</span></a> <a class="prev-week" title="eine Woche zurück" href="/essen-trinken/speiseplaene/mensa-offenburg/?tx_swfrspeiseplan_pi1%5BweekToShow%5D=0&amp;tx_swfrspeiseplan_pi1%5Baction%5D=show&amp;tx_swfrspeiseplan_pi1%5Bcontroller%5D=Speiseplan&amp;cHash=ad074b11cc01a680e4c0d0675dd1f91c"><img src="/fileadmin/templates/images/keil-grau-links.png" width="16" height="16" alt="" /><span class="d-inline d-sm-none">vorherige Woche</span></a>
</div> </div>
<div class="col-md-10"> <div class="col-md-10">
<ul class="nav classic-tabs tabs-primary" role="tablist"> <ul class="nav classic-tabs tabs-primary" role="tablist">
@ -13,7 +13,7 @@
<li class="col-md-2"><a href="#tab-sat" class="nav-link" data-toggle="tab" role="tab">Sa 14.03.</a></li> <li class="col-md-2"><a href="#tab-sat" class="nav-link" data-toggle="tab" role="tab">Sa 14.03.</a></li>
</ul> </ul>
</div> </div>
<div class="col-md-1 col-xs-6 pull-right"><a class="next-week text-right" title="eine Woche weiter" href="/de/essen-trinken/speiseplaene/mensa-offenburg/?tx_swfrspeiseplan_pi1%5BweekToShow%5D=2&amp;tx_swfrspeiseplan_pi1%5Baction%5D=show&amp;tx_swfrspeiseplan_pi1%5Bcontroller%5D=Speiseplan&amp;cHash=3c3048ebdd7f42a104bd780a0a6a0fd1"><span class="d-inline d-sm-none">nächste Woche</span><img src="/fileadmin/templates/images/keil-grau-rechts.png" width="16" height="16" alt="" /></a></div> <div class="col-md-1 col-xs-6 pull-right"><a class="next-week text-right" title="eine Woche weiter" href="/essen-trinken/speiseplaene/mensa-offenburg/?tx_swfrspeiseplan_pi1%5BweekToShow%5D=2&amp;tx_swfrspeiseplan_pi1%5Baction%5D=show&amp;tx_swfrspeiseplan_pi1%5Bcontroller%5D=Speiseplan&amp;cHash=3c3048ebdd7f42a104bd780a0a6a0fd1"><span class="d-inline d-sm-none">nächste Woche</span><img src="/fileadmin/templates/images/keil-grau-rechts.png" width="16" height="16" alt="" /></a></div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-sm-4"> <div class="col-sm-4">
@ -34,12 +34,12 @@
</div> </div>
<div class="col-sm-4 pt-3"> <div class="col-sm-4 pt-3">
<div class="hide-with-allergenes"> <div class="hide-with-allergenes">
<p><a download="Mensa_Offenburg_KW_11-2020.pdf" title="Wochenplan in Farbe herunterladen" target="_blank" href="/de/essen-trinken/speiseplaene/mensa-offenburg/?type=99&amp;tx_swfrspeiseplan_pi1%5BweekToShow%5D=1&amp;tx_swfrspeiseplan_pi1%5Bcolored%5D=1&amp;tx_swfrspeiseplan_pi1%5Bort%5D=651&amp;tx_swfrspeiseplan_pi1%5Baction%5D=buildPdf&amp;tx_swfrspeiseplan_pi1%5Bcontroller%5D=Speiseplan&amp;cHash=4de091579c564e42f79473da2701f179"><i class="fas fa-file-download" aria-hidden="true"></i> Wochenplan farbig</a></p> <p><a download="Mensa_Offenburg_KW_11-2020.pdf" title="Wochenplan in Farbe herunterladen" target="_blank" href="/essen-trinken/speiseplaene/mensa-offenburg/?type=99&amp;tx_swfrspeiseplan_pi1%5BweekToShow%5D=1&amp;tx_swfrspeiseplan_pi1%5Bcolored%5D=1&amp;tx_swfrspeiseplan_pi1%5Bort%5D=651&amp;tx_swfrspeiseplan_pi1%5Baction%5D=buildPdf&amp;tx_swfrspeiseplan_pi1%5Bcontroller%5D=Speiseplan&amp;cHash=4de091579c564e42f79473da2701f179"><i class="fas fa-file-download" aria-hidden="true"></i> Wochenplan farbig</a></p>
<p><a download="Mensa_Offenburg_KW_11-2020.pdf" title="Wochenplan in schwarz-weiß herunterladen" target="_blank" href="/de/essen-trinken/speiseplaene/mensa-offenburg/?type=99&amp;tx_swfrspeiseplan_pi1%5BweekToShow%5D=1&amp;tx_swfrspeiseplan_pi1%5Bcolored%5D=0&amp;tx_swfrspeiseplan_pi1%5Bort%5D=651&amp;tx_swfrspeiseplan_pi1%5Baction%5D=buildPdf&amp;tx_swfrspeiseplan_pi1%5Bcontroller%5D=Speiseplan&amp;cHash=84edf4562bdc95f103b70ef99e4d7af6"><i class="fas fa-file-download" aria-hidden="true"></i> Wochenplan s/w</a></p> <p><a download="Mensa_Offenburg_KW_11-2020.pdf" title="Wochenplan in schwarz-weiß herunterladen" target="_blank" href="/essen-trinken/speiseplaene/mensa-offenburg/?type=99&amp;tx_swfrspeiseplan_pi1%5BweekToShow%5D=1&amp;tx_swfrspeiseplan_pi1%5Bcolored%5D=0&amp;tx_swfrspeiseplan_pi1%5Bort%5D=651&amp;tx_swfrspeiseplan_pi1%5Baction%5D=buildPdf&amp;tx_swfrspeiseplan_pi1%5Bcontroller%5D=Speiseplan&amp;cHash=84edf4562bdc95f103b70ef99e4d7af6"><i class="fas fa-file-download" aria-hidden="true"></i> Wochenplan s/w</a></p>
</div> </div>
<div class="show-with-allergenes"> <div class="show-with-allergenes">
<p><a download="Mensa_Offenburg_KW_11-2020.pdf" title="Wochenplan in Farbe herunterladen" target="_blank" href="/de/essen-trinken/speiseplaene/mensa-offenburg/?type=99&amp;tx_swfrspeiseplan_pi1%5BweekToShow%5D=1&amp;tx_swfrspeiseplan_pi1%5Bcolored%5D=1&amp;tx_swfrspeiseplan_pi1%5Bort%5D=651&amp;tx_swfrspeiseplan_pi1%5Baction%5D=buildPdfAllergenes&amp;tx_swfrspeiseplan_pi1%5Bcontroller%5D=Speiseplan&amp;cHash=51f0f1e0083f9ef48038920dfb676eb6"><i class="fas fa-file-download" aria-hidden="true"></i> Wochenplan farbig</a></p> <p><a download="Mensa_Offenburg_KW_11-2020.pdf" title="Wochenplan in Farbe herunterladen" target="_blank" href="/essen-trinken/speiseplaene/mensa-offenburg/?type=99&amp;tx_swfrspeiseplan_pi1%5BweekToShow%5D=1&amp;tx_swfrspeiseplan_pi1%5Bcolored%5D=1&amp;tx_swfrspeiseplan_pi1%5Bort%5D=651&amp;tx_swfrspeiseplan_pi1%5Baction%5D=buildPdfAllergenes&amp;tx_swfrspeiseplan_pi1%5Bcontroller%5D=Speiseplan&amp;cHash=51f0f1e0083f9ef48038920dfb676eb6"><i class="fas fa-file-download" aria-hidden="true"></i> Wochenplan farbig</a></p>
<p><a download="Mensa_Offenburg_KW_11-2020.pdf" title="Wochenplan in schwarz-weiß herunterladen" target="_blank" href="/de/essen-trinken/speiseplaene/mensa-offenburg/?type=99&amp;tx_swfrspeiseplan_pi1%5BweekToShow%5D=1&amp;tx_swfrspeiseplan_pi1%5Bcolored%5D=0&amp;tx_swfrspeiseplan_pi1%5Bort%5D=651&amp;tx_swfrspeiseplan_pi1%5Baction%5D=buildPdfAllergenes&amp;tx_swfrspeiseplan_pi1%5Bcontroller%5D=Speiseplan&amp;cHash=c3a9d1eafce78d8f8d281c6060be989c"><i class="fas fa-file-download" aria-hidden="true"></i> Wochenplan s/w</a></p> <p><a download="Mensa_Offenburg_KW_11-2020.pdf" title="Wochenplan in schwarz-weiß herunterladen" target="_blank" href="/essen-trinken/speiseplaene/mensa-offenburg/?type=99&amp;tx_swfrspeiseplan_pi1%5BweekToShow%5D=1&amp;tx_swfrspeiseplan_pi1%5Bcolored%5D=0&amp;tx_swfrspeiseplan_pi1%5Bort%5D=651&amp;tx_swfrspeiseplan_pi1%5Baction%5D=buildPdfAllergenes&amp;tx_swfrspeiseplan_pi1%5Bcontroller%5D=Speiseplan&amp;cHash=c3a9d1eafce78d8f8d281c6060be989c"><i class="fas fa-file-download" aria-hidden="true"></i> Wochenplan s/w</a></p>
</div> </div>
</div> </div>
<div class="col-sm-4 pt-3"> <div class="col-sm-4 pt-3">
@ -510,4 +510,4 @@
</div> </div>
</div> </div>
</div> </div>
</div> </div>