Skip to content

Commit

Permalink
Merge branch 'main' into feature/kino-api
Browse files Browse the repository at this point in the history
# Conflicts:
#	client/go.mod
#	client/go.sum
#	docker-compose.yaml
#	server/api/tumdev/campus_backend.pb.go
#	server/backend/cron/cronjobs.go
#	server/backend/migration/migration.go
#	server/model/crontab.go
  • Loading branch information
CommanderStorm committed Sep 20, 2023
2 parents 98e1ebf + 6dd457c commit 19b87b1
Show file tree
Hide file tree
Showing 25 changed files with 1,212 additions and 796 deletions.
6 changes: 4 additions & 2 deletions .env
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
ENVIRONMENT=dev
DB_NAME=campus_db
DB_ROOT_PASSWORD=secret_root_password
DB_PORT=3306

APNS_KEY_ID=
APNS_TEAM_ID=
APNS_P8_FILE_PATH=/secrets/AuthKey_XXXX.p8

ENVIRONMENT=dev

SENTRY_DSN=

CAMPUS_API_TOKEN=
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ The following environment variables need to be set for the server to work proper
* [REQUIRED] `APNS_KEY_ID`: The key ID of the APNs key => APNs Key needs to be downloaded from the Apple Developer Portal the name of the file also contains the key ID.
* [REQUIRED] `APNS_TEAM_ID`: The team ID of the iOS app can be found in AppStoreConnect.
* [REQUIRED] `APNS_P8_FILE_PATH`: The path to the APNs key file (e.g. `/secrets/AuthKey_XXXX.p8`) in the docker container. The file itself needs to exist in the same directory as the `docker-compose.yml` file and called `apns_auth_key.p8`.
* [REQUIRED] `CAMPUS_API_TOKEN`: A token used to authenticate with TUMonline (used for example for the grades)

## InfluxDB
InfluxDB can be used to store metrics.
Expand Down
2 changes: 1 addition & 1 deletion client/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module github.com/TUM-Dev/Campus-Backend/client
go 1.21

require (
github.com/TUM-Dev/Campus-Backend/server v0.0.0-20230919162132-71bec88330f7
github.com/TUM-Dev/Campus-Backend/server v0.0.0-20230920003329-6dd457cded13
github.com/sirupsen/logrus v1.9.3
google.golang.org/grpc v1.58.1
)
Expand Down
4 changes: 2 additions & 2 deletions client/go.sum
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
github.com/TUM-Dev/Campus-Backend/server v0.0.0-20230919162132-71bec88330f7 h1:TDgiN5Z1vi3V0Qo94MIXURiD9+U7TGiRtiUIqN/rulo=
github.com/TUM-Dev/Campus-Backend/server v0.0.0-20230919162132-71bec88330f7/go.mod h1:fjoLL3rbdY6wTRJIksekT2p3OUp5ocFfXjB/avV/TVI=
github.com/TUM-Dev/Campus-Backend/server v0.0.0-20230920003329-6dd457cded13 h1:dhTgR4yvPICGPP1xVdGm1BI//RmvjpMokCZbKC1TL3E=
github.com/TUM-Dev/Campus-Backend/server v0.0.0-20230920003329-6dd457cded13/go.mod h1:fjoLL3rbdY6wTRJIksekT2p3OUp5ocFfXjB/avV/TVI=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,19 @@ spec:
- name: ENVIRONMENT
value: prod
- name: MensaCronDisabled
value: "false"
value: "true"
- name: APNS_P8_FILE_PATH
value: /etc/apns_auth_key.p8
- name: SENTRY_DSN
valueFrom:
secretKeyRef:
name: backend-api-keys
key: SENTRY_DSN
- name: CAMPUS_API_TOKEN
valueFrom:
secretKeyRef:
name: backend-api-keys
key: CAMPUS_API_TOKEN
- name: DB_DSN
value: "{{ $db.username }}:{{ $db.password }}@tcp(tca-backend-mariadb.{{ $.Values.namespace }}.svc.cluster.local:3306)/{{ $db.database }}?charset=utf8mb4&parseTime=True&loc=Local"
- name: APNS_KEY_ID
Expand Down Expand Up @@ -105,6 +110,7 @@ metadata:
app.kubernetes.io/part-of: tum-campus-app
app.kubernetes.io/name: backend-v2
data:
CAMPUS_API_TOKEN: {{ $.Values.backend.campusApiToken | b64enc }}
SENTRY_DSN: {{ $.Values.backend.sentry.dsn | b64enc }}
apns_auth_key.p8: {{ $.Values.backend.apns.auth_key }}
APNS_KEY_ID: {{ $.Values.backend.apns.key_id | b64enc }}
Expand Down
1 change: 1 addition & 0 deletions deployment/charts/backend/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ mariadb:


backend:
campusApiToken: changeme-changeme-changeme
sentry:
dsn: changeme-changeme-changeme
apns:
Expand Down
1 change: 1 addition & 0 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ services:
- APNS_P8_FILE_PATH=${APNS_P8_FILE_PATH}
- MensaCronDisabled=false
- OMDB_API_KEY=${OMDB_API_KEY}
- CAMPUS_API_TOKEN=${CAMPUS_API_TOKEN}
volumes:
- backend-storage:/Storage
- ./apns_auth_key.p8:${APNS_P8_FILE_PATH}
Expand Down
1,497 changes: 754 additions & 743 deletions server/api/tumdev/campus_backend.pb.go

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions server/api/tumdev/campus_backend.proto
Original file line number Diff line number Diff line change
Expand Up @@ -230,18 +230,19 @@ message Room {
string name = 9;
}

message NewsItem {
message News {
int64 id = 1;
string title = 2;
string text = 3;
string link = 4;
string image_url = 5;
string source = 6;
google.protobuf.Timestamp created = 7;
google.protobuf.Timestamp date = 8;
}

message GetNewsReply {
repeated NewsItem news = 1;
repeated News news = 1;
}

message GetNewsRequest {
Expand Down
10 changes: 7 additions & 3 deletions server/api/tumdev/campus_backend.swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -761,7 +761,7 @@
"type": "array",
"items": {
"type": "object",
"$ref": "#/definitions/apiNewsItem"
"$ref": "#/definitions/apiNews"
}
}
},
Expand Down Expand Up @@ -1279,7 +1279,7 @@
"type": "array",
"items": {
"type": "object",
"$ref": "#/definitions/apiNewsItem"
"$ref": "#/definitions/apiNews"
}
}
}
Expand Down Expand Up @@ -1562,7 +1562,7 @@
}
}
},
"apiNewsItem": {
"apiNews": {
"type": "object",
"properties": {
"id": {
Expand All @@ -1587,6 +1587,10 @@
"created": {
"type": "string",
"format": "date-time"
},
"date": {
"type": "string",
"format": "date-time"
}
}
},
Expand Down
56 changes: 26 additions & 30 deletions server/backend/campus_api/campusApi.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,56 +4,52 @@ package campus_api
import (
"encoding/xml"
"errors"
"fmt"
"io"
"net/http"

"github.com/TUM-Dev/Campus-Backend/server/model"
log "github.com/sirupsen/logrus"
)

const (
CampusApiUrl = "https://campus.tum.de/tumonline"
CampusQueryToken = "pToken"
CampusGradesPath = "/wbservicesbasic.noten"
)
func FetchExamResultsPublished(token string) (*model.TUMAPIPublishedExamResults, error) {
var examResultsPublished model.TUMAPIPublishedExamResults
err := RequestCampusApi("/wbservicesbasic.pruefungenErgebnisse", token, &examResultsPublished)
if err != nil {
return nil, err
}

var (
ErrCannotCreateRequest = errors.New("cannot create http request")
ErrWhileFetchingGrades = errors.New("error while fetching grades")
ErrorWhileUnmarshalling = errors.New("error while unmarshalling")
)
return &examResultsPublished, nil
}

func FetchGrades(token string) (*model.IOSGrades, error) {

requestUrl := CampusApiUrl + CampusGradesPath
req, err := http.NewRequest(http.MethodGet, requestUrl, nil)

var grades model.IOSGrades
err := RequestCampusApi("/wbservicesbasic.noten", token, &grades)
if err != nil {
log.WithError(err).Error("Failed to create api-request")
return nil, ErrCannotCreateRequest
return nil, err
}

q := req.URL.Query()
q.Add(CampusQueryToken, token)

req.URL.RawQuery = q.Encode()
return &grades, nil
}

resp, err := http.DefaultClient.Do(req)
func RequestCampusApi(path string, token string, response any) error {
requestUrl := fmt.Sprintf("https://campus.tum.de/tumonline%s?pToken=%s", path, token)
resp, err := http.Get(requestUrl)
if err != nil {
log.WithError(err).Error("failed to fetch grades")
return nil, ErrWhileFetchingGrades
log.WithError(err).WithField("path", path).Error("Error while fetching url")
return errors.New("error while fetching " + path)
}
defer func(Body io.ReadCloser) {
if err := Body.Close(); err != nil {
log.WithError(err).Error("Could not close body")
err := Body.Close()
if err != nil {
log.WithError(err).Error("Error while closing body")
}
}(resp.Body)

var grades model.IOSGrades
if err = xml.NewDecoder(resp.Body).Decode(&grades); err != nil {
log.WithError(err).Error("could not unmarshall grades")
return nil, ErrorWhileUnmarshalling
if err = xml.NewDecoder(resp.Body).Decode(&response); err != nil {
log.WithError(err).WithField("path", path).Error("Error while unmarshalling")
return errors.New("error while unmarshalling")
}

return &grades, nil
return nil
}
8 changes: 7 additions & 1 deletion server/backend/cron/cronjobs.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ const (
CanteenHeadcount = "canteenHeadCount"
IOSNotifications = "iosNotifications"
IOSActivityReset = "iosActivityReset"
NewExamResultsHook = "newExamResultsHook"
MovieType = "movie"

/* MensaType = "mensa"
Expand Down Expand Up @@ -59,7 +60,7 @@ func (c *CronService) Run() error {
var res []model.Crontab

c.db.Model(&model.Crontab{}).
Where("`interval` > 0 AND (lastRun+`interval`) < ? AND type IN (?, ?, ?, ?, ?, ?, ?, ?)",
Where("`interval` > 0 AND (lastRun+`interval`) < ? AND type IN (?, ?, ?, ?, ?, ?, ?, ?, ?)",
time.Now().Unix(),
NewsType,
FileDownloadType,
Expand All @@ -68,6 +69,7 @@ func (c *CronService) Run() error {
CanteenHeadcount,
IOSNotifications,
IOSActivityReset,
NewExamResultsHook,
MovieType,
).
Scan(&res)
Expand Down Expand Up @@ -105,12 +107,16 @@ func (c *CronService) Run() error {
if env.IsMensaCronActive() {
g.Go(c.averageRatingComputation)
}
case NewExamResultsHook:
g.Go(func() error { return c.newExamResultsHookCron() })
case MovieType:
g.Go(func() error { return c.movieCron() })
/*
TODO: Implement handlers for other cronjobs
case MensaType:
g.Go(func() error { return c.mensaCron() })
case KinoType:
g.Go(func() error { return c.kinoCron() })
case RoomfinderType:
g.Go(func() error { return c.roomFinderCron() })
case AlarmType:
Expand Down
15 changes: 15 additions & 0 deletions server/backend/cron/newExamResultsHook.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package cron

import (
"github.com/TUM-Dev/Campus-Backend/server/backend/ios_notifications/ios_device"
"github.com/TUM-Dev/Campus-Backend/server/backend/new_exam_results_hook/new_exam_results_scheduling"
)

func (c *CronService) newExamResultsHookCron() error {
repo := new_exam_results_scheduling.NewRepository(c.db)
devicesRepo := ios_device.NewRepository(c.db)

service := new_exam_results_scheduling.NewService(repo, devicesRepo, c.APNs)

return service.HandleScheduledCron()
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ func (r *Repository) ApnsUrl() string {
if env.IsProd() {
return ApnsProductionURL
}

return ApnsDevelopmentURL
}

Expand Down Expand Up @@ -87,7 +86,6 @@ func (r *Repository) SendNotification(notification *model.IOSNotificationPayload
url := r.ApnsUrl() + "/3/device/" + notification.DeviceId
body, _ := notification.MarshalJSON()

client := r.httpClient
req, _ := http.NewRequest(http.MethodPost, url, bytes.NewBuffer(body))

// can be e.g. alert or background
Expand All @@ -99,7 +97,7 @@ func (r *Repository) SendNotification(notification *model.IOSNotificationPayload
bearer := r.Token.GenerateNewTokenIfExpired()
req.Header.Set("authorization", "bearer "+bearer)

resp, err := client.Do(req)
resp, err := r.httpClient.Do(req)
if err != nil {
log.WithError(err).Error("Could not send notification")
return nil, ErrCouldNotSendNotification
Expand Down
67 changes: 67 additions & 0 deletions server/backend/migration/20230530000000.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package migration

import (
_ "embed"
"time"

"github.com/TUM-Dev/Campus-Backend/server/model"
"github.com/go-gormigrate/gormigrate/v2"
"github.com/guregu/null"
"gorm.io/gorm"
)

type PublishedExamResult struct {
Date time.Time
ExamID string `gorm:"primary_key"`
LectureTitle string
LectureType string
LectureSem string
Published bool
}

type NewExamResultsSubscriber struct {
CallbackUrl string `gorm:"primary_key"`
ApiKey null.String
CreatedAt time.Time `gorm:"autoCreateTime"`
LastNotifiedAt null.Time
}

func (m TumDBMigrator) migrate20230530000000() *gormigrate.Migration {
return &gormigrate.Migration{
ID: "20230530000000",
Migrate: func(tx *gorm.DB) error {

if err := tx.AutoMigrate(
&PublishedExamResult{},
&NewExamResultsSubscriber{},
); err != nil {
return err
}

err := SafeEnumMigrate(tx, model.Crontab{}, "type", "newExamResultsHook")
if err != nil {
return err
}

return tx.Create(&model.Crontab{
Interval: 60 * 10, // Every 10 minutes
Type: null.StringFrom("newExamResultsHook"),
}).Error
},
Rollback: func(tx *gorm.DB) error {
if err := tx.Migrator().DropTable(&PublishedExamResult{}); err != nil {
return err
}
if err := tx.Migrator().DropTable(&NewExamResultsSubscriber{}); err != nil {
return err
}

err := SafeEnumRollback(tx, model.Crontab{}, "type", "newExamResultsHook")
if err != nil {
return err
}

return tx.Delete(&model.Crontab{}, "type = ?", "newExamResultsHook").Error
},
}
}
1 change: 1 addition & 0 deletions server/backend/migration/migration.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ func (m TumDBMigrator) Migrate() error {
m.migrate20221210000000(),
m.migrate20230825000000(),
m.migrate20230904000000(),
m.migrate20230530000000(),
m.migrate20230904100000(),
})
err := mig.Migrate()
Expand Down
Loading

0 comments on commit 19b87b1

Please sign in to comment.