Initial QSfera import

This commit is contained in:
Курнат Андрей
2026-06-07 10:20:04 +03:00
commit 2315f25754
16485 changed files with 4826827 additions and 0 deletions
+128
View File
@@ -0,0 +1,128 @@
package roles
import (
"context"
"time"
"github.com/qsfera/server/pkg/log"
settingsmsg "github.com/qsfera/server/protogen/gen/qsfera/messages/settings/v0"
settingssvc "github.com/qsfera/server/protogen/gen/qsfera/services/settings/v0"
"github.com/opencloud-eu/reva/v2/pkg/store"
microstore "go-micro.dev/v4/store"
"google.golang.org/protobuf/encoding/protojson"
)
const (
cacheDatabase = "qsfera-pkg"
cacheTableName = "roles"
cacheTTL = 24 * time.Hour
)
// Manager manages a cache of roles by fetching unknown roles from the settings.RoleService.
type Manager struct {
logger log.Logger
roleCache microstore.Store
roleService settingssvc.RoleService
}
// NewManager returns a new instance of Manager.
func NewManager(o ...Option) Manager {
opts := newOptions(o...)
nStore := store.Create(opts.storeOptions...)
return Manager{
roleCache: nStore,
roleService: opts.roleService,
}
}
// List returns all roles that match the given roleIDs.
func (m *Manager) List(ctx context.Context, roleIDs []string) []*settingsmsg.Bundle {
// get from cache
result := make([]*settingsmsg.Bundle, 0)
lookup := make([]string, 0)
for _, roleID := range roleIDs {
if records, err := m.roleCache.Read(roleID, microstore.ReadFrom(cacheDatabase, cacheTableName)); err != nil {
lookup = append(lookup, roleID)
} else {
role := &settingsmsg.Bundle{}
found := false
for _, record := range records {
if record.Key == roleID {
if err := protojson.Unmarshal(record.Value, role); err == nil {
// if we can unmarshal the role, append it to the result
// otherwise assume the role wasn't found (data was damaged and
// we need to get the role again)
result = append(result, role)
found = true
break
}
}
}
if !found {
lookup = append(lookup, roleID)
}
}
}
// if there are roles missing, fetch them from the RoleService
if len(lookup) > 0 {
request := &settingssvc.ListBundlesRequest{
BundleIds: lookup,
}
res, err := m.roleService.ListRoles(ctx, request)
if err != nil {
m.logger.Debug().Err(err).Msg("failed to fetch roles by roleIDs")
return nil
}
for _, role := range res.Bundles {
jsonbytes, _ := protojson.Marshal(role)
record := &microstore.Record{
Key: role.Id,
Value: jsonbytes,
Expiry: cacheTTL,
}
err := m.roleCache.Write(
record,
microstore.WriteTo(cacheDatabase, cacheTableName),
microstore.WriteTTL(cacheTTL),
)
if err != nil {
m.logger.Debug().Err(err).Msg("failed to cache roles")
}
result = append(result, role)
}
}
return result
}
// FindPermissionByID searches for a permission-setting by the permissionID, but limited to the given roleIDs
func (m *Manager) FindPermissionByID(ctx context.Context, roleIDs []string, permissionID string) *settingsmsg.Setting {
for _, role := range m.List(ctx, roleIDs) {
for _, setting := range role.Settings {
if setting.Id == permissionID {
return setting
}
}
}
return nil
}
// FindRoleIdsForUser returns all roles that are assigned to the supplied userid
func (m *Manager) FindRoleIDsForUser(ctx context.Context, userID string) ([]string, error) {
req := &settingssvc.ListRoleAssignmentsRequest{AccountUuid: userID}
assignmentResponse, err := m.roleService.ListRoleAssignments(ctx, req)
if err != nil {
return nil, err
}
roleIDs := make([]string, 0, len(assignmentResponse.Assignments))
for _, assignment := range assignmentResponse.Assignments {
roleIDs = append(roleIDs, assignment.RoleId)
}
return roleIDs, nil
}
+48
View File
@@ -0,0 +1,48 @@
package roles
import (
"github.com/qsfera/server/pkg/log"
settingssvc "github.com/qsfera/server/protogen/gen/qsfera/services/settings/v0"
"go-micro.dev/v4/store"
)
// Options are all the possible options.
type Options struct {
storeOptions []store.Option
logger log.Logger
roleService settingssvc.RoleService
}
// Option mutates option
type Option func(*Options)
// Logger sets a preconfigured logger
func Logger(logger log.Logger) Option {
return func(o *Options) {
o.logger = logger
}
}
// RoleService provides endpoints for fetching roles.
func RoleService(rs settingssvc.RoleService) Option {
return func(o *Options) {
o.roleService = rs
}
}
// StoreOptions are the options for the store
func StoreOptions(storeOpts []store.Option) Option {
return func(o *Options) {
o.storeOptions = storeOpts
}
}
func newOptions(opts ...Option) Options {
o := Options{}
for _, v := range opts {
v(&o)
}
return o
}
+22
View File
@@ -0,0 +1,22 @@
package roles
import (
"context"
"encoding/json"
"github.com/qsfera/server/pkg/middleware"
"go-micro.dev/v4/metadata"
)
// ReadRoleIDsFromContext extracts roleIDs from the metadata context and returns them as []string
func ReadRoleIDsFromContext(ctx context.Context) (roleIDs []string, ok bool) {
roleIDsJSON, ok := metadata.Get(ctx, middleware.RoleIDs)
if !ok {
return nil, false
}
err := json.Unmarshal([]byte(roleIDsJSON), &roleIDs)
if err != nil {
return nil, false
}
return roleIDs, true
}