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

Add #201 Ability to configure default organisation and types on initi… #203

Merged
merged 1 commit into from
Oct 11, 2023
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
20 changes: 20 additions & 0 deletions src/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,23 @@ type WebhooksConfig struct {
KafkaConfig KafkaConfig
}

// Organization organization data type
type Organization struct {
Name string `valid:"required"`
Location string `valid:"required"`
Description string
EulaURL string
}

type OrgType struct {
Name string `valid:"required"`
}

type User struct {
Username string `valid:"required"`
Password string `valid:"required"`
}

// Configuration data type
type Configuration struct {
DataBase struct {
Expand All @@ -80,6 +97,9 @@ type Configuration struct {
Password string
}
ApplicationMode string
Organization Organization
Type OrgType
User User
Iam Iam
Twilio Twilio
Firebase Firebase
Expand Down
10 changes: 0 additions & 10 deletions src/handlerv1/organization_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,16 +134,6 @@ func GetOrganizationByID(w http.ResponseWriter, r *http.Request) {
w.Write(response)
}

// GetOrganizationId Gets an organization Id.
func GetOrganizationId() (string, error) {
org, err := org.GetOrganization()
if err != nil {
log.Printf("Failed to get organization")
return "", err
}
return org.ID.Hex(), err
}

type orgUpdateReq struct {
Name string
Location string
Expand Down
37 changes: 17 additions & 20 deletions src/main/main.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package main

import (
"flag"
"fmt"
"log"
"net/http"
Expand All @@ -25,13 +24,6 @@ import (
"github.com/spf13/cobra"
)

func handleCommandLineArgs() (configFileName string) {
fconfigFileName := flag.String("config", "config-development.json", "configuration file")
flag.Parse()

return *fconfigFileName
}

func main() {

var rootCmd = &cobra.Command{Use: "bb-consent-api"}
Expand All @@ -45,47 +37,47 @@ func main() {
Run: func(cmd *cobra.Command, args []string) {

configFile := "/opt/bb-consent/api/config/" + configFileName
config, err := config.Load(configFile)
loadedConfig, err := config.Load(configFile)
if err != nil {
log.Printf("Failed to load config file %s \n", configFile)
panic(err)
}

log.Printf("config file: %s loaded\n", configFile)

err = database.Init(config)
err = database.Init(loadedConfig)
if err != nil {
panic(err)
}
log.Println("Data base session opened")

webhooks.Init(config)
webhooks.Init(loadedConfig)
log.Println("Webhooks configuration initialized")

err = kafkaUtils.Init(config)
err = kafkaUtils.Init(loadedConfig)
if err != nil {
panic(err)
}
log.Println("Kafka producer client initialised")

handler.IamInit(config)
handler.IamInit(loadedConfig)
log.Println("Iam initialized")

email.Init(config)
email.Init(loadedConfig)
log.Println("Email initialized")

token.Init(config)
token.Init(loadedConfig)
log.Println("Token initialized")

err = notifications.Init()
if err != nil {
panic(err)
}

firebaseUtils.Init(config)
firebaseUtils.Init(loadedConfig)
log.Println("Firebase initialized")

middleware.ApplicationModeInit(config)
middleware.ApplicationModeInit(loadedConfig)
log.Println("Application mode initialized")

// setup casbin auth rules
Expand All @@ -94,6 +86,11 @@ func main() {
panic(err)
}

// If the application starts in single tenant mode then create/update organisation, type, admin logic
if loadedConfig.ApplicationMode == config.SingleTenant {
SingleTenantConfiguration(loadedConfig)
}

router := mux.NewRouter()
httppathsv1.SetRoutes(router, authEnforcer)
httppathsv2.SetRoutes(router, authEnforcer)
Expand All @@ -114,20 +111,20 @@ func main() {

configFile := "/opt/bb-consent/api/config/" + configFileName

config, err := config.Load(configFile)
loadedConfig, err := config.Load(configFile)
if err != nil {
log.Printf("Failed to load config file %s \n", configFile)
panic(err)
}
log.Printf("config file: %s loaded\n", configFile)

err = database.Init(config)
err = database.Init(loadedConfig)
if err != nil {
panic(err)
}
log.Println("Data base session opened")

webhookdispatcher.WebhookDispatcherInit(config)
webhookdispatcher.WebhookDispatcherInit(loadedConfig)
},
}

Expand Down
134 changes: 134 additions & 0 deletions src/main/single_tenant.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
package main

import (
"log"

"github.com/bb-consent/api/src/common"
"github.com/bb-consent/api/src/config"
"github.com/bb-consent/api/src/org"
"github.com/bb-consent/api/src/orgtype"
"github.com/bb-consent/api/src/user"
"go.mongodb.org/mongo-driver/mongo"
)

func createOrganisationAdmin(config *config.Configuration) user.User {
u, err := user.GetByEmail(config.User.Username)
if err != nil {
log.Println("Failed to get user, creating new user.")
u, err = user.RegisterUser(config.User, config.Iam)
if err != nil {
log.Println("failed to create user")
panic(err)
}
}

return u
}

func createOrganisationType(config *config.Configuration) orgtype.OrgType {
orgType, err := orgtype.GetFirstType()
if err != nil {
if err == mongo.ErrNoDocuments {
log.Printf("Organization type doesn't exist, creating organization type.")
orgType, err = orgtype.AddOrganizationType(config.Type)
if err != nil {
log.Println("failed to add organization")
panic(err)
}
} else {
log.Println("failed to find organization")
panic(err)
}
}

return orgType
}

func addOrganisationAdminRole(organisationAdminId string, organisationId string) {
_, err := user.AddRole(organisationAdminId, user.Role{RoleID: common.GetRoleID("Admin"), OrgID: organisationId})
if err != nil {
log.Printf("Failed to update user : %v roles for org: %v", organisationAdminId, organisationId)
panic(err)
}
}

func createOrganisation(config *config.Configuration, orgType orgtype.OrgType, organisationAdminId string) org.Organization {
organization, err := org.GetFirstOrganization()
if err != nil {
if err == mongo.ErrNoDocuments {
log.Printf("Organization doesn't exist, creating organization.")
organization, err = org.AddOrganization(config.Organization, orgType.ID.Hex(), organisationAdminId)
if err != nil {
log.Println("failed to add organization")
panic(err)
}
// Add roles to organisation admin user
addOrganisationAdminRole(organisationAdminId, organization.ID.Hex())

} else {
log.Println("failed to find organization")
panic(err)
}
}

return organization
}

func deleteAllOrganisationTypes() {
typesCount, err := orgtype.GetTypesCount()
if err != nil {
log.Println("failed to count types")
panic(err)
}

if typesCount > 1 {
_, err := orgtype.DeleteAllTypes()
if err != nil {
log.Println("failed to delete organizations")
panic(err)
}
}
}

func deleteAllOrganisations() {
count, err := org.GetOrganizationsCount()
if err != nil {
log.Println("failed to count organization")
panic(err)
}
if count > 1 {
_, err := org.DeleteAllOrganizations()
if err != nil {
log.Println("failed to delete organizations")
panic(err)
}
}
}

// SingleTenantConfiguration If the application starts in single tenant mode then create/update organisation, type, admin logic
func SingleTenantConfiguration(config *config.Configuration) {

// Following is not allowed:
// 1. Updation of organisation is not allowed
// 2. Updation of organistaion type is not allowed
// 3. Updation of organisation admin is not allowed
// Note: Database has to be cleared if new organisation, type or admin has to be added

// If there is more than 1 organisation or type, delete all (this is a temporary and will be removed later)
deleteAllOrganisationTypes()
deleteAllOrganisations()

// Create an organisation admin
organisationAdmin := createOrganisationAdmin(config)
organisationAdminId := organisationAdmin.ID.Hex()

// TODO: If wrong password is provided, the application panics
user.GetOrganisationAdminToken(config.User, config.Iam)

// Create organisation type
orgType := createOrganisationType(config)

// Create organisation
createOrganisation(config, orgType, organisationAdminId)

}
7 changes: 6 additions & 1 deletion src/middleware/middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (

"github.com/bb-consent/api/src/apikey"
handler "github.com/bb-consent/api/src/handlerv1"
"github.com/bb-consent/api/src/org"
"github.com/bb-consent/api/src/rbac"
"github.com/casbin/casbin/v2"
"github.com/gorilla/mux"
Expand Down Expand Up @@ -204,9 +205,11 @@ func Authorize(e *casbin.Enforcer) Middleware {
}

var ApplicationMode string
var Organization config.Organization

func ApplicationModeInit(config *config.Configuration) {
ApplicationMode = config.ApplicationMode
Organization = config.Organization
}

// SetApplicationMode sets application modes for routes to either single tenant or multi tenant
Expand All @@ -218,12 +221,14 @@ func SetApplicationMode() Middleware {
return func(w http.ResponseWriter, r *http.Request) {

if ApplicationMode == config.SingleTenant {
organizationId, err := handler.GetOrganizationId()

organization, err := org.GetFirstOrganization()
if err != nil {
m := "failed to find organization"
common.HandleError(w, http.StatusBadRequest, m, err)
return
}
organizationId := organization.ID.Hex()
r.Header.Set(config.OrganizationId, organizationId)
}

Expand Down
Loading