Skip to content
Open
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
5 changes: 2 additions & 3 deletions cmd/app/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,8 @@ import (
// @BasePath /
// @schemes http

// @securitydefinitions.apikey Auth
// @in header
// @name Authorization
// @securitydefinitions.oauth2.password OAuth2Password
// @tokenUrl http://localhost:8080/api/v1/auth/login
func main() {
cfg, err := config.NewConfig()
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module ssr

go 1.17
go 1.19

require (
github.com/golang-jwt/jwt v3.2.2+incompatible
Expand Down
70 changes: 35 additions & 35 deletions internal/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,45 +4,44 @@ package app
import (
"fmt"
"github.com/labstack/echo/v4"
m "github.com/labstack/echo/v4/middleware"
echoSwagger "github.com/swaggo/echo-swagger"
"github.com/labstack/echo/v4/middleware"
"net/http"
"ssr/config"
"ssr/internal/controller/http"
uc "ssr/internal/usecase"
repo "ssr/internal/usecase/repo_pg"
ctrl "ssr/internal/controller/http"
"ssr/internal/service"
"ssr/internal/service/repo_pg"
"ssr/pkg/logger"
"ssr/pkg/misc"
"ssr/pkg/postgres"
_ "ssr/swagger"
"strings"
)

func setupMiddlewares(server *echo.Echo, cfg *config.Config) {
server.Use(m.CORS())
server.Use(m.Logger())
server.Use(m.Recover())
server.Use(m.JWTWithConfig(m.JWTConfig{
Claims: &misc.AppJWTClaims{},
SigningKey: []byte(cfg.SigningKey),
ContextKey: "ctx",
Skipper: func(c echo.Context) bool {
// Skip middleware if 'login' or 'swagger'
path := c.Request().URL.Path
split := strings.Split(path, "/")
return split[2] == "auth" || split[1] == "swagger"
},
}))
func setupMiddlewares(server *echo.Echo) {
server.Use(middleware.CORS())
server.Use(middleware.Logger())
server.Use(middleware.Recover())
}

func setupUC(server *echo.Echo, pg *postgres.Postgres, l *logger.Logger, cfg *config.Config) {
authUC := uc.NewAuth(repo.NewAuthPgRepo(pg, l), l, cfg.Auth.TokenExp, []byte(cfg.Auth.SigningKey))
profileUC := uc.NewProfile(repo.NewProfilePgRepo(pg, l), l)
bidUC := uc.NewBid(repo.NewSSRPgRepo(pg, l), l)
workUC := uc.NewWork(repo.NewWorkPgRepo(pg, l), repo.NewSSRPgRepo(pg, l), l)
ssrUC := uc.NewSSR(repo.NewSSRPgRepo(pg, l), l)
feedBackUC := uc.NewFeedback(repo.NewFeedback(pg, l), l)
func makeInjections(server *echo.Echo, pg *postgres.Postgres, l *logger.Logger, cfg *config.Config) {
relationRepo := repo_pg.NewRelation(pg, l)
workRepo := repo_pg.NewWork(pg, l)
waypointRepo := repo_pg.NewWaypointRepo(pg, l)
userRepo := repo_pg.NewUser(pg, l)
studentRepo := repo_pg.NewStudent(pg, l)
supervisorRepo := repo_pg.NewSupervisor(pg, l)

http.NewRouter(server, l, authUC, profileUC, bidUC, bidUC, workUC, workUC, ssrUC, feedBackUC)
authService := service.NewAuth(userRepo, l, cfg.Auth.TokenExp, []byte(cfg.Auth.SigningKey))
profileService := service.NewProfile(studentRepo, supervisorRepo, l)
workService := service.NewWork(workRepo, relationRepo, studentRepo, supervisorRepo, waypointRepo, l)
relationService := service.NewRelation(relationRepo, l)

ctrl.NewRouter(
server,
l,
cfg,
authService,
profileService,
workService,
relationService,
)
}

func Run(cfg *config.Config) {
Expand All @@ -56,9 +55,10 @@ func Run(cfg *config.Config) {
defer pg.Close()

server := echo.New()
setupMiddlewares(server, cfg)
setupUC(server, pg, loggerObject, cfg)
setupMiddlewares(server)
makeInjections(server, pg, loggerObject, cfg)

server.GET("/swagger*", echoSwagger.WrapHandler)
server.Logger.Fatal(server.Start(cfg.HTTP.Port))
if err := server.Start(cfg.HTTP.Port); err != http.ErrServerClosed {
server.Logger.Fatal(err)
}
}
24 changes: 11 additions & 13 deletions internal/controller/http/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,47 +4,45 @@ import (
"fmt"
"github.com/labstack/echo/v4"
"net/http"
"ssr/internal/usecase"
"ssr/pkg/logger"
)

type authRoutes struct {
l logger.Interface
uc usecase.IUsecaseAuth
type auth struct {
l logger.Interface
service AuthService
}

// ShowAccount godoc
// @Summary Login into account
// @Tags auth
// @Accept x-www-form-urlencoded
// @Produce json
// @Param username formData string true "User email"
// @Param password formData string true "User password"
// @Param username formData string true "UserFull email"
// @Param password formData string true "UserFull password"
// @Success 200 {object} dto.LoginResponse
// @Failure 401
// @Failure 500
// @Router /api/auth/login [post]
func (r *authRoutes) login(ctx echo.Context) error {
func (ctrl *auth) login(ctx echo.Context) error {
email := ctx.FormValue("username")
password := ctx.FormValue("password")

r.l.Debug(fmt.Sprintf("Email %s; Password: %s", email, password))
ctrl.l.Debug(fmt.Sprintf("Email %s; Password: %s", email, password))

respDTO, err := r.uc.Login(email, password)
respDTO, err := ctrl.service.Login(email, password)
if err != nil {
return echo.ErrUnauthorized
}

return ctx.JSON(http.StatusOK, respDTO)
}

func NewAuthRoutes(router *echo.Group, l logger.Interface, uc usecase.IUsecaseAuth) {
ar := &authRoutes{l, uc}
func NewAuthRoutes(router *echo.Group, l logger.Interface, service AuthService) {
ctrl := &auth{l, service}

g := router.Group("/auth")

{
g.POST("/login", ar.login)
g.POST("/login", ctrl.login)
}

}
26 changes: 26 additions & 0 deletions internal/controller/http/interfaces.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package http

import (
"ssr/internal/dto"
)

type (
AuthService interface {
Login(email, password string) (*dto.LoginResponse, error)
}
ProfileService interface {
GetStudentProfile(userID int) (*dto.Student, error)
GetSupervisorProfile(userID int) (*dto.Supervisor, error)
}
RelationsService interface {
GetPlenty(studentID, supervisorID int) (*dto.RelationPlenty, error)
Create(data *dto.RelationCreateReq) (*dto.RelationCreateResp, error)
Update(data *dto.RelationUpdateReq) (*dto.RelationResp, error)
Get(RelationID int) (*dto.RelationResp, error)
}
WorkService interface {
Get(workID int) (*dto.WorkFullResp, error)
GetStudentWorks(studentID int) (*dto.StudentViewWorkPlenty, error)
GetSupervisorWorks(supervisorID int) (*dto.SupervisorViewWorkPlenty, error)
}
)
22 changes: 19 additions & 3 deletions internal/controller/http/middlewares/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package middlewares

import (
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
"ssr/config"
"ssr/pkg/misc"
"strings"
)
Expand All @@ -10,11 +12,17 @@ func CheckRole(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
split := strings.Split(c.Request().URL.Path, "/")

// /api/<role>/... -> ["", "api", "<role>" , ...]
expRole := split[2]
// /api/<role>/... -> ["", "api", "vNo", "<role>" , ...]

if len(split) < 4 {
return echo.ErrForbidden
}
expRole := split[3]
_, recRole := misc.ExtractCtx(c)

if recRole != expRole {
mapping := map[string]string{"st": "students", "sv": "supervisors"}

if mapping[recRole] != expRole {
return echo.ErrForbidden
}

Expand All @@ -25,3 +33,11 @@ func CheckRole(next echo.HandlerFunc) echo.HandlerFunc {
return nil
}
}

func MakeAuthMiddleware(config *config.Config) echo.MiddlewareFunc {
return middleware.JWTWithConfig(middleware.JWTConfig{
Claims: &misc.AppJWTClaims{},
SigningKey: []byte(config.SigningKey),
ContextKey: "ctx",
})
}
119 changes: 119 additions & 0 deletions internal/controller/http/relation.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package http

import (
"github.com/labstack/echo/v4"
"net/http"
"ssr/config"
"ssr/internal/controller/http/middlewares"
"ssr/internal/dto"
"ssr/pkg/logger"
"strconv"
)

type relation struct {
l logger.Interface
relationService RelationsService
}

// ShowAccount godoc
// @Summary Create relation
// @Tags relation
// @Accept json
// @Param CreateRelation body dto.RelationCreateReq true "Relation data"
// @Produce json
// @Success 201 {object} dto.RelationCreateResp
// @Router /api/v1/relations/ [post]
// @Security OAuth2Password
func (ctrl *relation) create(ctx echo.Context) error {
reqDTO := &dto.RelationCreateReq{}

if err := ctx.Bind(reqDTO); err != nil {
return echo.ErrBadRequest
}

respDTO, err := ctrl.relationService.Create(reqDTO)
if err != nil {
return echo.ErrInternalServerError
}

return ctx.JSON(http.StatusCreated, respDTO)
}

// ShowAccount godoc
// @Summary Update relation
// @Tags relation
// @Accept json
// @Param CreateRelation body dto.RelationUpdateReq true "Relation data"
// @Produce json
// @Success 200 {object} dto.RelationResp
// @Router /api/v1/relations/ [patch]
// @Security OAuth2Password
func (ctrl *relation) update(ctx echo.Context) error {
reqDTO := &dto.RelationUpdateReq{}

if err := ctx.Bind(reqDTO); err != nil {
return echo.ErrBadRequest
}

respDTO, err := ctrl.relationService.Update(reqDTO)
if err != nil {
return echo.ErrInternalServerError
}

return ctx.JSON(http.StatusCreated, respDTO)
}

// ShowAccount godoc
// @Summary Get relations
// @Tags relation
// @Produce json
// @Param student_id query int false "Student ID"
// @Param supervisor_id query int false "Supervisor ID"
// @Success 200 {object} dto.RelationPlenty
// @Failure 404
// @Router /api/v1/relations/ [get]
// @Security OAuth2Password
func (ctrl *relation) getPlenty(ctx echo.Context) error {
studentID, _ := strconv.Atoi(ctx.QueryParam("student_id"))
supervisorID, _ := strconv.Atoi(ctx.QueryParam("supervisor_id"))

if studentID < 0 || supervisorID < 0 {
return echo.NewHTTPError(400, map[string]string{"err": "Bad request", "msg": "Parameter (student_id, supervisor_id) must be positive"})
}

if studentID == 0 && supervisorID == 0 {
return echo.NewHTTPError(400, map[string]string{"err": "Bad request", "msg": "Must be passed at least one parameter (student_id, supervisor_id)"})
}

if studentID != 0 && supervisorID != 0 {
return echo.NewHTTPError(400, map[string]string{"err": "Bad request", "msg": "Must be passed only on parameter (student_id, supervisor_id)"})
}

respDTO, err := ctrl.relationService.GetPlenty(studentID, supervisorID)
if err != nil {
return err
}

return ctx.JSON(http.StatusOK, respDTO)
}

func NewRelationRoutes(
router *echo.Group,
l logger.Interface,
config *config.Config,
relationsService RelationsService,
) {
ctrl := &relation{
l,
relationsService,
}

relations := router.Group("/relations", middlewares.MakeAuthMiddleware(config))

{
relations.GET("/", ctrl.getPlenty)
relations.POST("/", ctrl.create)
relations.PATCH("/", ctrl.update)
}

}
Loading