Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added documentation #75

Merged
merged 10 commits into from
Oct 23, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@
- Guided walkthrough
- Audio annotations and TTS (Text-to-Speech)

## External Links
This project is hosted on a VPS, deployed and running via Docker containers. Source code is hosted on GitHub, and static code analysis is run by SonarCloud to ensure code maintainability.
- [Fableous](https://fableous.daystram.com)
- [GitHub](https://github.com/deco-finter/fableous)
- [DockerHub](https://hub.docker.com/r/daystram/fableous)
- [SonarCloud](https://sonarcloud.io/project/overview?id=deco-finter_fableous)

## Service

The application is divided into two parts:
Expand Down
5 changes: 5 additions & 0 deletions fableous-be/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,20 @@ import (
"github.com/spf13/viper"
)

// AppConfig is a global reference to the application config.
var AppConfig Config

// Config is the base application configuration struct.
type Config struct {
Version string
Port int
Environment string
Debug bool

// Directory to store static gallery files
StaticDir string

// PostgreSQL database configuration
DBHost string
DBPort int
DBDatabase string
Expand All @@ -25,6 +29,7 @@ type Config struct {
JWTSecret string
}

// InitializeAppConfig loads AppConfig from environment variables.
func InitializeAppConfig() {
viper.SetConfigName(".env") // allow directly reading from .env file
viper.SetConfigType("env")
Expand Down
1 change: 1 addition & 0 deletions fableous-be/constants/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ import (
)

const (
// AuthenticationTimeout is the expiry duration for issued JWT tokens.
AuthenticationTimeout = time.Hour * 24 * 2
)
1 change: 1 addition & 0 deletions fableous-be/constants/classroom.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package constants

const (
// ClassroomTokenLength is the length of the session token.
ClassroomTokenLength = 4
)
6 changes: 5 additions & 1 deletion fableous-be/constants/router.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package constants

const (
// RouterKeyIsAuthenticated is the key for the request authentication status injected by the auth middleware.
RouterKeyIsAuthenticated = "is_authenticated"
RouterKeyUserID = "user_id"

// RouterKeyUserID is the key for the requesting userID injected by the auth middleware.
// Empty if the request is not authenticated.
RouterKeyUserID = "user_id"
)
2 changes: 2 additions & 0 deletions fableous-be/controllers/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/deco-finter/fableous/fableous-be/handlers"
)

// POSTLogin handles login request.
func POSTLogin(c *gin.Context) {
var err error
var user datatransfers.UserLogin
Expand All @@ -26,6 +27,7 @@ func POSTLogin(c *gin.Context) {
c.JSON(http.StatusOK, datatransfers.Response{})
}

// POSTRegister handles register request.
func POSTRegister(c *gin.Context) {
var err error
var user datatransfers.UserSignup
Expand Down
25 changes: 15 additions & 10 deletions fableous-be/controllers/classroom.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,28 +10,31 @@ import (
"github.com/deco-finter/fableous/fableous-be/handlers"
)

func GETClassroom(c *gin.Context) {
// GETClassroomList handles classroom list request.
func GETClassroomList(c *gin.Context) {
var err error
var classroomInfo datatransfers.ClassroomInfo
classroomInfo.ID = c.Param("classroom_id")
if classroomInfo, err = handlers.Handler.ClassroomGetOneByID(classroomInfo.ID); err != nil {
var classroomInfos []datatransfers.ClassroomInfo
userID := c.GetString(constants.RouterKeyUserID)
if classroomInfos, err = handlers.Handler.ClassroomGetAllByUserID(userID); err != nil {
c.JSON(http.StatusNotFound, datatransfers.Response{Error: "cannot find classroom"})
return
}
c.JSON(http.StatusOK, datatransfers.Response{Data: classroomInfo})
c.JSON(http.StatusOK, datatransfers.Response{Data: classroomInfos})
}

func GETClassroomList(c *gin.Context) {
// GETClassroom handles classroom detail request.
func GETClassroom(c *gin.Context) {
var err error
var classroomInfos []datatransfers.ClassroomInfo
userID := c.GetString(constants.RouterKeyUserID)
if classroomInfos, err = handlers.Handler.ClassroomGetAllByUserID(userID); err != nil {
var classroomInfo datatransfers.ClassroomInfo
classroomInfo.ID = c.Param("classroom_id")
if classroomInfo, err = handlers.Handler.ClassroomGetOneByID(classroomInfo.ID); err != nil {
c.JSON(http.StatusNotFound, datatransfers.Response{Error: "cannot find classroom"})
return
}
c.JSON(http.StatusOK, datatransfers.Response{Data: classroomInfos})
c.JSON(http.StatusOK, datatransfers.Response{Data: classroomInfo})
}

// POSTClassroom handles classroom creation request.
func POSTClassroom(c *gin.Context) {
var err error
var classroomInfo datatransfers.ClassroomInfo
Expand All @@ -47,6 +50,7 @@ func POSTClassroom(c *gin.Context) {
c.JSON(http.StatusOK, datatransfers.Response{Data: classroomInfo.ID})
}

// PUTClassroom handles classroom update request.
func PUTClassroom(c *gin.Context) {
var err error
var classroomInfo datatransfers.ClassroomInfo
Expand All @@ -69,6 +73,7 @@ func PUTClassroom(c *gin.Context) {
c.JSON(http.StatusOK, datatransfers.Response{})
}

// DELETEClassroom handles classroom deletion request.
func DELETEClassroom(c *gin.Context) {
var err error
var classroomInfo datatransfers.ClassroomInfo
Expand Down
1 change: 1 addition & 0 deletions fableous-be/controllers/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/deco-finter/fableous/fableous-be/utils"
)

// InitializeRouter initialize the gin router.
func InitializeRouter() (router *gin.Engine) {
router = gin.Default()
router.Use(
Expand Down
2 changes: 2 additions & 0 deletions fableous-be/controllers/middleware/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/deco-finter/fableous/fableous-be/handlers"
)

// AuthMiddleware is a middleware that checks for a valid JWT token.
func AuthMiddleware(c *gin.Context) {
var token string
if token = strings.TrimPrefix(c.GetHeader("Authorization"), "Bearer "); token == "" {
Expand All @@ -38,6 +39,7 @@ func AuthMiddleware(c *gin.Context) {
c.Next()
}

// parseToken parses a JWT token and returns the claims.
func parseToken(tokenString, secret string) (claims datatransfers.JWTClaims, err error) {
if token, err := jwt.ParseWithClaims(tokenString, &claims, func(token *jwt.Token) (interface{}, error) {
return []byte(secret), nil
Expand Down
1 change: 1 addition & 0 deletions fableous-be/controllers/middleware/cors.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/gin-gonic/gin"
)

// CORSMiddleware allows cross-origin resource sharing.
func CORSMiddleware(c *gin.Context) {
cors.New(cors.Config{
AllowOrigins: []string{"*"},
Expand Down
2 changes: 2 additions & 0 deletions fableous-be/controllers/ping.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import (
"github.com/deco-finter/fableous/fableous-be/config"
)

// GETPing is a healthcheck endpoint.
// It reponds with the application version.
func GETPing(c *gin.Context) {
c.JSON(http.StatusOK, map[string]string{"version": config.AppConfig.Version})
}
7 changes: 7 additions & 0 deletions fableous-be/controllers/session.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/deco-finter/fableous/fableous-be/handlers"
)

// GETSessionList handles session list for a classroom request.
func GETSessionList(c *gin.Context) {
var err error
var sessionInfos []datatransfers.SessionInfo
Expand All @@ -24,6 +25,7 @@ func GETSessionList(c *gin.Context) {
c.JSON(http.StatusOK, datatransfers.Response{Data: sessionInfos})
}

// GETSession handles session detail request.
func GETSession(c *gin.Context) {
var err error
var sessionInfo datatransfers.SessionInfo
Expand All @@ -37,6 +39,8 @@ func GETSession(c *gin.Context) {
c.JSON(http.StatusOK, datatransfers.Response{Data: sessionInfo})
}

// GETOngoinSession handles ongoing session request.
// 404 if no ongoing session is found.
func GETOngoingSession(c *gin.Context) {
var err error
var sessionInfo datatransfers.SessionInfo
Expand All @@ -50,6 +54,7 @@ func GETOngoingSession(c *gin.Context) {
c.JSON(http.StatusOK, datatransfers.Response{Data: sessionInfo})
}

// POSTSession handles session creation request.
func POSTSession(c *gin.Context) {
var err error
var classroomInfo datatransfers.ClassroomInfo
Expand Down Expand Up @@ -84,6 +89,7 @@ func POSTSession(c *gin.Context) {
c.JSON(http.StatusOK, datatransfers.Response{Data: sessionInfo.ID})
}

// PUTSession handles session update request.
func PUTSession(c *gin.Context) {
var err error
var classroomInfo datatransfers.ClassroomInfo
Expand Down Expand Up @@ -112,6 +118,7 @@ func PUTSession(c *gin.Context) {
c.JSON(http.StatusOK, datatransfers.Response{})
}

// DELETESession handles session deletion request.
func DELETESession(c *gin.Context) {
var err error
var classroomInfo datatransfers.ClassroomInfo
Expand Down
2 changes: 2 additions & 0 deletions fableous-be/controllers/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/deco-finter/fableous/fableous-be/handlers"
)

// GETUser handles user detail request.
func GETUser(c *gin.Context) {
var err error
var userInfo datatransfers.UserInfo
Expand All @@ -20,6 +21,7 @@ func GETUser(c *gin.Context) {
c.JSON(http.StatusOK, datatransfers.Response{Data: userInfo})
}

// PUTUser handles user update request.
func PUTUser(c *gin.Context) {
var err error
var user datatransfers.UserUpdate
Expand Down
2 changes: 2 additions & 0 deletions fableous-be/controllers/websocket.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
pb "github.com/deco-finter/fableous/fableous-be/protos"
)

// GETConnectHubWS handles WebSocket connection from the hub.
func GETConnectHubWS(c *gin.Context) {
var err error
var classroomInfo datatransfers.ClassroomInfo
Expand All @@ -30,6 +31,7 @@ func GETConnectHubWS(c *gin.Context) {
_ = handlers.Handler.ConnectHubWS(c, classroomInfo.ID)
}

// GETConnectControllerWS handles WebSocket connection from the controller.
func GETConnectControllerWS(c *gin.Context) {
var err error
var classroomToken string
Expand Down
1 change: 1 addition & 0 deletions fableous-be/datatransfers/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"time"
)

// JWTClaims is the JWT claims struct.
type JWTClaims struct {
ID string `json:"sub,omitempty"`
ExpiresAt int64 `json:"exp,omitempty"`
Expand Down
1 change: 1 addition & 0 deletions fableous-be/datatransfers/classroom.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"time"
)

// ClassroomInfo is the data transfer object for the Classroom entity.
type ClassroomInfo struct {
ID string `json:"id" binding:"-"`
UserID string `json:"-" binding:"-"`
Expand Down
1 change: 1 addition & 0 deletions fableous-be/datatransfers/response.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package datatransfers

// Response is the API response wrapper.
type Response struct {
Code int `json:"code,omitempty"`
Data interface{} `json:"data,omitempty"`
Expand Down
2 changes: 2 additions & 0 deletions fableous-be/datatransfers/session.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ package datatransfers

import "time"

// SessionUpdate is the data transfer object used for updating the Session entity.
type SessionUpdate struct {
ID string `json:"id" binding:"-"`
ClassroomID string `json:"-" binding:"-"`
Title string `json:"title" binding:"required"`
Description string `json:"description" binding:"required"`
}

// SessionInfo is the data transfer object for the Session entity.
type SessionInfo struct {
ID string `json:"id" binding:"-"`
ClassroomID string `json:"-" binding:"-"`
Expand Down
4 changes: 4 additions & 0 deletions fableous-be/datatransfers/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,26 @@ import (
"time"
)

// UserLogin is the data transfer object used for logging in a user.
type UserLogin struct {
Email string `json:"email" binding:"required"`
Password string `json:"password" binding:"required"`
}

// UserSignup is the data transfer object used for signing up a new user.
type UserSignup struct {
Name string `json:"name" binding:"required"`
Email string `json:"email" binding:"required"`
Password string `json:"password" binding:"required"`
}

// UserUpdate is the data transfer object used for updating the User entity.
type UserUpdate struct {
Name string `json:"name" binding:"-"`
Email string `json:"email" binding:"-"`
}

// UserInfo is the data transfer object for the User entity.
type UserInfo struct {
ID string `json:"id" uri:"id"`
Name string `json:"name"`
Expand Down
2 changes: 2 additions & 0 deletions fableous-be/handlers/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/deco-finter/fableous/fableous-be/models"
)

// Authenticate issues a token for the given user credentials
func (m *module) Authenticate(credentials datatransfers.UserLogin) (token string, err error) {
var user models.User
if user, err = m.db.userOrmer.GetOneByEmail(credentials.Email); err != nil {
Expand All @@ -24,6 +25,7 @@ func (m *module) Authenticate(credentials datatransfers.UserLogin) (token string
return generateToken(user)
}

// generateToken generates a JWT token for the given user
func generateToken(user models.User) (string, error) {
now := time.Now()
expiry := time.Now().Add(constants.AuthenticationTimeout)
Expand Down
6 changes: 6 additions & 0 deletions fableous-be/handlers/classroom.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/deco-finter/fableous/fableous-be/models"
)

// ClassroomGetByID returns a classroom by its ID.
func (m *module) ClassroomGetOneByID(id string) (classroomInfo datatransfers.ClassroomInfo, err error) {
var classroom models.Classroom
if classroom, err = m.db.classroomOrmer.GetOneByID(id); err != nil {
Expand All @@ -25,6 +26,7 @@ func (m *module) ClassroomGetOneByID(id string) (classroomInfo datatransfers.Cla
return
}

// ClassroomGetAllByUserID returns all classrooms owned by a user.
func (m *module) ClassroomGetAllByUserID(userID string) (classroomInfos []datatransfers.ClassroomInfo, err error) {
var classrooms []models.Classroom
classroomInfos = make([]datatransfers.ClassroomInfo, 0)
Expand All @@ -44,6 +46,7 @@ func (m *module) ClassroomGetAllByUserID(userID string) (classroomInfos []datatr
return
}

// ClassroomInsert inserts a new classroom.
func (m *module) ClassroomInsert(classroomInfo datatransfers.ClassroomInfo) (classroomID string, err error) {
if classroomID, err = m.db.classroomOrmer.Insert(models.Classroom{
UserID: classroomInfo.UserID,
Expand All @@ -54,6 +57,7 @@ func (m *module) ClassroomInsert(classroomInfo datatransfers.ClassroomInfo) (cla
return
}

// ClassroomUpdate updates a classroom.
func (m *module) ClassroomUpdate(classroomInfo datatransfers.ClassroomInfo) (err error) {
if err = m.db.classroomOrmer.Update(models.Classroom{
ID: classroomInfo.ID,
Expand All @@ -64,6 +68,8 @@ func (m *module) ClassroomUpdate(classroomInfo datatransfers.ClassroomInfo) (err
return
}

// ClassroomDeleteByID deletes a classroom by its ID.
// It also stops any ongoing session and removes all its sessions' static files.
func (m *module) ClassroomDeleteByID(classroomID string) (err error) {
m.sessions.mutex.Lock()
for classroomToken, sess := range m.sessions.keys {
Expand Down
Loading