change subdomain

main
alex 2024-09-06 17:15:24 +02:00
parent 7fda97d09e
commit 0538e8b3ea
6 changed files with 225 additions and 2 deletions

View File

@ -27,6 +27,7 @@ type CreateOrganizationResponse struct {
Session string Session string
} }
// swagger:model GetOrganizationSettingsResponse
type GetOrganizationSettingsResponse struct { type GetOrganizationSettingsResponse struct {
Subdomain string Subdomain string
CompanyName string CompanyName string
@ -35,7 +36,23 @@ type GetOrganizationSettingsResponse struct {
BannerUrl string BannerUrl string
} }
// swagger:model UpdateOrganizationSettingsRequest
type UpdateOrganizationSettingsRequest struct { type UpdateOrganizationSettingsRequest struct {
CompanyName string CompanyName string
PrimaryColor string PrimaryColor string
} }
// swagger:model UpdateOrganizationFileParam
type UpdateOrganizationFileParam struct {
Type string
}
// swagger:model IsSubdomainAvailableResponse
type IsSubdomainAvailableResponse struct {
Available bool
}
// swagger:model SubdomainParam
type SubdomainParam struct {
Subdomain string
}

View File

@ -110,7 +110,11 @@ func IsFileTypeAllowed(contentType string, allowedContentTypes []string) bool {
} }
func DeleteFile(filePath string) { func DeleteFile(filePath string) {
os.Remove(filePath) err := os.Remove(config.Cfg.FolderPaths.PublicStatic + filePath)
if err != nil {
log.Error().Msgf("Failed to delete file: %v", err)
}
} }
func CreateFolderStructureIfNotExists(folderPath string) { func CreateFolderStructureIfNotExists(folderPath string) {
@ -123,6 +127,13 @@ func CreateFolderStructureIfNotExists(folderPath string) {
// GetFullImagePath returns the database path and the public path for the image // GetFullImagePath returns the database path and the public path for the image
func GetFullImagePath(organizationId string, lessonId string) (databasePath string, publicPath string) { func GetFullImagePath(organizationId string, lessonId string) (databasePath string, publicPath string) {
if lessonId == "" {
return fmt.Sprintf(
"o/%s/", organizationId),
fmt.Sprintf(
"%s/o/%s/", config.Cfg.FolderPaths.PublicStatic, organizationId)
}
return fmt.Sprintf( return fmt.Sprintf(
"o/%s/l/%s/", organizationId, lessonId), "o/%s/l/%s/", organizationId, lessonId),
fmt.Sprintf( fmt.Sprintf(

View File

@ -197,7 +197,7 @@ func UpdateLessonPreviewThumbnail(c *fiber.Ctx) error {
// --- // ---
// summary: Update lesson preview thumbnail. // summary: Update lesson preview thumbnail.
// consumes: // consumes:
// - application/json // - multipart/form-data
// produces: // produces:
// - application/json // - application/json
// parameters: // parameters:

View File

@ -103,3 +103,89 @@ func CreateOrganization(c *fiber.Ctx) error {
Session: session, Session: session,
}) })
} }
func IsSubdomainAvailable(c *fiber.Ctx) error {
// swagger:operation GET /organization/subdomain/{subdomain} organization isSubdomainAvailable
// ---
// summary: Check if subdomain is available
// produces:
// - application/json
// parameters:
// - name: subdomain
// in: path
// required: true
// type: string
// responses:
// '200':
// description: Subdomain is available
// schema:
// "$ref": "#/definitions/IsSubdomainAvailableResponse"
// '400':
// description: Invalid subdomain
// '500':
// description: Failed to check subdomain
var params structs.SubdomainParam
if err := rsutils.ParamsParserHelper(c, &params); err != nil {
return c.SendStatus(fiber.StatusBadRequest)
}
var organization structs.Organization
database.DB.Select("Id").Where("subdomain = ?", params.Subdomain).First(&organization)
if organization.Id != "" {
return c.JSON(structs.IsSubdomainAvailableResponse{
Available: false,
})
}
return c.JSON(structs.IsSubdomainAvailableResponse{
Available: true,
})
}
func UpdateSubdomain(c *fiber.Ctx) error {
// swagger:operation PATCH /organization/subdomain/{subdomain} organization updateSubdomain
// ---
// summary: Update organization subdomain
// consumes:
// - application/json
// produces:
// - application/json
// parameters:
// - name: subdomain
// in: path
// required: true
// type: string
// responses:
// '200':
// description: Subdomain updated successfully
// '400':
// description: Invalid request body
// '500':
// description: Failed to update subdomain
var params structs.SubdomainParam
if err := rsutils.ParamsParserHelper(c, &params); err != nil {
return c.SendStatus(fiber.StatusBadRequest)
}
organization := structs.Organization{
Id: c.Locals("organizationId").(string),
}
database.DB.Select("subdomain").Model(organization).First(&organization)
if organization.Subdomain == "" {
return c.SendStatus(fiber.StatusBadRequest)
}
database.DB.Model(&organization).Update("subdomain", params.Subdomain)
return c.JSON(fiber.Map{
"status": "success",
})
}

View File

@ -1,9 +1,13 @@
package organization package organization
import ( import (
"strings"
"github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2"
"github.com/google/uuid"
"lms.de/backend/modules/database" "lms.de/backend/modules/database"
"lms.de/backend/modules/structs" "lms.de/backend/modules/structs"
"lms.de/backend/modules/utils"
) )
func GetOrganizationSettings(c *fiber.Ctx) error { func GetOrganizationSettings(c *fiber.Ctx) error {
@ -64,3 +68,105 @@ func UpdateOrganizationSettings(c *fiber.Ctx) error {
return c.SendStatus(fiber.StatusOK) return c.SendStatus(fiber.StatusOK)
} }
func UpdateOrganizationFile(c *fiber.Ctx) error {
// swagger:operation POST /organization/file/{type} organization updateOrganizationFiles
// ---
// summary: Update files
// consumes:
// - multipart/form-data
// produces:
// - application/json
// parameters:
// - name: logo
// in: formData
// type: file
// required: false
// - name: banner
// in: formData
// type: file
// required: false
// responses:
// '200':
// description: Files updated successfully
// '400':
// description: Invalid request body
// '500':
// description: Failed to update files
var params structs.UpdateOrganizationFileParam
if err := c.ParamsParser(&params); err != nil {
return c.SendStatus(fiber.StatusBadRequest)
}
fileHeader, err := c.FormFile("file")
if err != nil {
return c.SendStatus(fiber.StatusBadRequest)
}
if params.Type == "logo" || params.Type == "banner" {
if fileHeader.Size > utils.MaxImageSize {
return c.SendStatus(fiber.StatusBadRequest)
}
if !utils.IsFileTypeAllowed(fileHeader.Header.Get("Content-Type"), utils.AcceptedImageFileTypes) {
return c.SendStatus(fiber.StatusBadRequest)
}
} else {
return c.SendStatus(fiber.StatusBadRequest)
}
// get current file
organization := structs.Organization{}
selectField := "logo_url"
if params.Type == "banner" {
selectField = "banner_url"
}
database.DB.Model(&structs.Organization{
Id: c.Locals("organizationId").(string),
}).Select(selectField).First(&organization)
// delete current file
if organization.LogoUrl != "" {
utils.DeleteFile(organization.LogoUrl)
}
if organization.BannerUrl != "" {
utils.DeleteFile(organization.BannerUrl)
}
fileName := uuid.New().String() + "." + strings.Split(fileHeader.Header["Content-Type"][0], "/")[1]
databasePath, publicPath := utils.GetFullImagePath(c.Locals("organizationId").(string), "")
utils.CreateFolderStructureIfNotExists(publicPath)
update := structs.Organization{}
if params.Type == "logo" {
update.LogoUrl = databasePath + fileName
} else {
update.BannerUrl = databasePath + fileName
}
database.DB.Model(&structs.Organization{
Id: c.Locals("organizationId").(string),
}).Updates(update)
if err := c.SaveFile(fileHeader, publicPath+fileName); err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
"error": "Failed to save file",
})
}
return c.JSON(fiber.Map{
"Data": databasePath + fileName,
})
}

View File

@ -24,6 +24,9 @@ func SetupRoutes(app *fiber.App) {
o.Get("/team/members", handleOrganizationSubdomain, requestAccessValidation, organization.GetTeamMembers) o.Get("/team/members", handleOrganizationSubdomain, requestAccessValidation, organization.GetTeamMembers)
o.Get("/settings", handleOrganizationSubdomain, requestAccessValidation, organization.GetOrganizationSettings) o.Get("/settings", handleOrganizationSubdomain, requestAccessValidation, organization.GetOrganizationSettings)
o.Patch("/settings", handleOrganizationSubdomain, requestAccessValidation, organization.UpdateOrganizationSettings) o.Patch("/settings", handleOrganizationSubdomain, requestAccessValidation, organization.UpdateOrganizationSettings)
o.Post("/file/:type", handleOrganizationSubdomain, requestAccessValidation, organization.UpdateOrganizationFile)
o.Get("/subdomain/:subdomain", organization.IsSubdomainAvailable)
o.Patch("/subdomain/:subdomain", handleOrganizationSubdomain, requestAccessValidation, organization.UpdateSubdomain)
u := v1.Group("/user") u := v1.Group("/user")
u.Post("/auth/login", handleOrganizationSubdomain, user.UserLogin) u.Post("/auth/login", handleOrganizationSubdomain, user.UserLogin)