Skip to content

Commit

Permalink
Course and user endpoints for API v2 (#1429)
Browse files Browse the repository at this point in the history
* Refactor courses.go and index.go to avoid code duplication

* Setup API v2 with gRPC and REST proxy

* Update tumlive.go to run API v2

* Add custom errors and semester endpoints

* Add user endpoints and authentication for API v2

* Add course endpoints

* Add proto files and API docs; updated dependencies

* Update endpoints to use google.protobuf.Empty

* Update go.work.sum

* Move api_v2 go files and docs into api_v2/server

* Update generate.sh

* refactor: rename api_v2 to apiv2 and update related imports
carlobortolan authored Jan 29, 2025
1 parent d888fcd commit be8cc02
Showing 35 changed files with 11,266 additions and 776 deletions.
14 changes: 1 addition & 13 deletions api/courses.go
Original file line number Diff line number Diff line change
@@ -152,7 +152,7 @@ func (r coursesRoutes) getLive(c *gin.Context) {
}
// only show "enrolled" streams to users which are enrolled or admins
if courseForLiveStream.Visibility == "enrolled" {
if !isUserAllowedToWatchPrivateCourse(courseForLiveStream, tumLiveContext.User) {
if !tumLiveContext.User.IsAllowedToWatchPrivateCourse(courseForLiveStream) {
continue
}
}
@@ -406,18 +406,6 @@ func (r coursesRoutes) getCourseBySlug(c *gin.Context) {
c.JSON(http.StatusOK, courseDTO)
}

func isUserAllowedToWatchPrivateCourse(course model.Course, user *model.User) bool {
if user != nil {
for _, c := range user.Courses {
if c.ID == course.ID {
return true
}
}
return user.IsEligibleToWatchCourse(course)
}
return false
}

func (r coursesRoutes) createVOD(c *gin.Context) {
logger.Info("createVOD")
var req createVODReq
31 changes: 31 additions & 0 deletions apiv2/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# GOCAST API V2

This API is designed to be a user-friendly and easy-to-use interface for third party services. It provides access to all non-administrative features of the GoCast platform via gRPC methods and exposes a REST API proxy for easy access.

In the future, this API might be extended to include more features and endpoints and replace the current REST API.

## Documentation

You can find the docs for the new API [here](https://tum.live/api/v2/docs).

You can generate the code documentation using `godoc` and find it at [http://localhost:6060/pkg/github.com/TUM-Dev/gocast](`http://localhost:6060/pkg/github.com/TUM-Dev/gocast`).

## File structure

All proto messages can be found in `apiv2.proto`.
The actual endpoints are implemented in `<./endpoint.go>.go`, custom erros in `./errors` and helper functions such as parsers, custom database queries, etc. in `./helpers`.

## Config

Install protobuf by running `./apiv2/installBuf.sh`.

To generate the files in `./protobuf`, run:
`./apiv2/generate.sh`.

## Running the server

To build and start the new API, start GoCast as usual with:
`go run ./cmd/tumlive/tumlive.go`.

The gRPC server will be running on port 12544 and the API proxy on [localhost:8081/api/v2](http://localhost:8081/api/v2/status).<br>
The docs can be found at [http://localhost:8081/api/v2/docs](http://localhost:8081/api/v2/docs).
19 changes: 19 additions & 0 deletions apiv2/buf.gen.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
version: v1
plugins:
- name: go
out: protobuf
opt:
- paths=source_relative
- name: go-grpc
out: protobuf
opt:
- paths=source_relative
- name: grpc-gateway
out: protobuf
opt:
- paths=source_relative
- allow_repeated_fields_in_body=true
- name: openapiv2
out: docs
opt:
- allow_repeated_fields_in_body=true
2 changes: 2 additions & 0 deletions apiv2/buf.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Generated by buf. DO NOT EDIT.
version: v1
8 changes: 8 additions & 0 deletions apiv2/buf.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
version: v1
deps: []
lint:
use:
- DEFAULT
breaking:
use:
- FILE
45 changes: 45 additions & 0 deletions apiv2/errors/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Package errors provides helper functions for handling errors with specific HTTP status codes.
package errors

import (
"fmt"
"log/slog"
"net/http"

"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)

// WithStatus creates a new error with a specific HTTP status code and a given error message.
// It maps the HTTP status code to a corresponding gRPC status code.
// If the HTTP status code is not recognized, it logs a warning and uses gRPC's Unknown code.
// It returns a gRPC error with the mapped gRPC status code and the original error message.
func WithStatus(httpStatus int, err error) error {
var code codes.Code
switch httpStatus {
case http.StatusNotFound:
code = codes.NotFound
case http.StatusUnauthorized:
code = codes.Unauthenticated
case http.StatusForbidden:
code = codes.PermissionDenied
case http.StatusBadRequest:
code = codes.InvalidArgument
case http.StatusConflict:
code = codes.AlreadyExists
case http.StatusTooManyRequests:
code = codes.ResourceExhausted
case http.StatusNotImplemented:
code = codes.Unimplemented
case http.StatusServiceUnavailable:
code = codes.Unavailable
case http.StatusGatewayTimeout:
code = codes.DeadlineExceeded
case http.StatusInternalServerError:
code = codes.Unknown // default to 500
default:
slog.Warn("Unknown HTTP status code: ", "httpStatus", fmt.Sprintf("%d", httpStatus))
code = codes.Unknown
}
return status.Error(code, err.Error())
}
29 changes: 29 additions & 0 deletions apiv2/generate.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#!/bin/bash

# needs buf: https://docs.buf.build/installation#github-releases
BASEDIR=$(dirname "$0")
echo making sure that this script is run from $BASEDIR
pushd $BASEDIR > /dev/null

echo updating the generated files
export PATH="$PATH:$(go env GOPATH)/bin"
buf dep update || exit 1
buf generate || exit 1

echo making sure that all artifacts we don\'t need are cleaned up
rm -f google/api/*.go
rm -f google/api/*.swagger.json

echo moving the generated docs to the server directory
mv ./docs/server/apiv2.swagger.json ./server/docs || exit 1

echo making sure that all artifacts we don\'t need are cleaned up
rm -rf docs docs/google docs/protoc-gen-openapiv2 protobuf/google protobuf/protoc-gen-openapiv2

echo making sure that the generated files are formatted
go fmt server/*.go || exit 1
goimports -w server/*.go || exit 1
buf format -w --path server || exit 1

# clean up the stack
popd > /dev/null
31 changes: 31 additions & 0 deletions apiv2/google/api/annotations.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright 2015 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

syntax = "proto3";

package google.api;

import "google/api/http.proto";
import "google/protobuf/descriptor.proto";

option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations";
option java_multiple_files = true;
option java_outer_classname = "AnnotationsProto";
option java_package = "com.google.api";
option objc_class_prefix = "GAPI";

extend google.protobuf.MethodOptions {
// See `HttpRule`.
HttpRule http = 72295728;
}
Loading

0 comments on commit be8cc02

Please sign in to comment.