settings: Remove deprecated filesystem backend

We changed the default to `metadata` before the 2.0 release. This PR
alos removes the associated `SETTINGS_STORE_TYPE` and
`SETTINGS_DATA_PATH` settings as they are no longer needed with
`metadata` as the only available backend.
This commit is contained in:
Ralf Haferkamp
2024-05-13 14:50:02 +02:00
committed by Ralf Haferkamp
parent 4177f43cdb
commit 5b38fa149d
20 changed files with 9 additions and 1681 deletions
-2
View File
@@ -25,8 +25,6 @@ type Config struct {
GRPCClientTLS *shared.GRPCClientTLS `yaml:"grpc_client_tls"`
GrpcClient client.Client `yaml:"-"`
StoreType string `yaml:"store_type" env:"SETTINGS_STORE_TYPE" desc:"Store type configures the persistency driver. Supported values are 'metadata' and 'filesystem'. Note that the value 'filesystem' is considered deprecated." introductionVersion:"pre5.0"`
DataPath string `yaml:"data_path" env:"SETTINGS_DATA_PATH" desc:"The directory where the filesystem storage will store ocis settings. If not defined, the root directory derives from $OCIS_BASE_DATA_PATH:/settings." introductionVersion:"pre5.0"`
Metadata Metadata `yaml:"metadata_config"`
BundlesPath string `yaml:"bundles_path" env:"SETTINGS_BUNDLES_PATH" desc:"The path to a JSON file with a list of bundles. If not defined, the default bundles will be loaded." introductionVersion:"pre5.0"`
Bundles []*settingsmsg.Bundle `yaml:"-"`
@@ -3,11 +3,9 @@ package defaults
import (
"encoding/json"
"os"
"path"
"strings"
"time"
"github.com/owncloud/ocis/v2/ocis-pkg/config/defaults"
"github.com/owncloud/ocis/v2/ocis-pkg/structs"
"github.com/owncloud/ocis/v2/services/settings/pkg/config"
rdefaults "github.com/owncloud/ocis/v2/services/settings/pkg/store/defaults"
@@ -49,8 +47,6 @@ func DefaultConfig() *config.Config {
Addr: "127.0.0.1:9191",
Namespace: "com.owncloud.api",
},
StoreType: "metadata", // use metadata or filesystem
DataPath: path.Join(defaults.BaseDataPath(), "settings"),
SetupDefaultAssignments: false,
Metadata: config.Metadata{
GatewayAddress: "com.owncloud.api.storage-system",
+1 -51
View File
@@ -17,7 +17,6 @@ import (
"github.com/owncloud/ocis/v2/services/settings/pkg/config"
"github.com/owncloud/ocis/v2/services/settings/pkg/settings"
"github.com/owncloud/ocis/v2/services/settings/pkg/store/defaults"
filestore "github.com/owncloud/ocis/v2/services/settings/pkg/store/filesystem"
metastore "github.com/owncloud/ocis/v2/services/settings/pkg/store/metadata"
merrors "go-micro.dev/v4/errors"
"go-micro.dev/v4/metadata"
@@ -40,17 +39,7 @@ func NewService(cfg *config.Config, logger log.Logger) settings.ServiceHandler {
logger: logger,
}
switch cfg.StoreType {
default:
fallthrough
case "metadata":
service.manager = metastore.New(cfg)
case "filesystem":
fmt.Println("WARNING: filesystem store is deprecated and will be removed in the future. Please use metadata store instead.")
service.manager = filestore.New(cfg)
// TODO: if we want to further support filesystem store it should use default permissions from store/defaults/defaults.go instead using this duplicate
service.RegisterDefaultRoles()
}
service.manager = metastore.New(cfg)
return service
}
@@ -101,45 +90,6 @@ func (g Service) CheckPermission(ctx context.Context, req *cs3permissions.CheckP
}, nil
}
// RegisterDefaultRoles composes default roles and saves them. Skipped if the roles already exist.
func (g Service) RegisterDefaultRoles() {
// FIXME: we're writing default roles per service start (i.e. twice at the moment, for http and grpc server). has to happen only once.
for _, role := range generateBundlesDefaultRoles() {
bundleID := role.Extension + "." + role.Id
// check if the role already exists
bundle, _ := g.manager.ReadBundle(role.Id)
if bundle != nil {
g.logger.Debug().Str("bundleID", bundleID).Msg("bundle already exists. skipping.")
continue
}
// create the role
_, err := g.manager.WriteBundle(role)
if err != nil {
g.logger.Error().Err(err).Str("bundleID", bundleID).Msg("failed to register bundle")
}
g.logger.Debug().Str("bundleID", bundleID).Msg("successfully registered bundle")
}
for _, req := range generatePermissionRequests() {
_, err := g.manager.AddSettingToBundle(req.GetBundleId(), req.GetSetting())
if err != nil {
g.logger.Error().
Err(err).
Str("bundleID", req.GetBundleId()).
Interface("setting", req.GetSetting()).
Msg("failed to register permission")
}
}
if g.config.SetupDefaultAssignments {
for _, req := range g.defaultRoleAssignments() {
if _, err := g.manager.WriteRoleAssignment(req.AccountUuid, req.RoleId); err != nil {
g.logger.Error().Err(err).Msg("failed to register role assignment")
}
}
}
}
// TODO: check permissions on every request
// SaveBundle implements the BundleServiceHandler interface
@@ -1,10 +1,5 @@
package svc
import (
settingsmsg "github.com/owncloud/ocis/v2/protogen/gen/ocis/messages/settings/v0"
settingssvc "github.com/owncloud/ocis/v2/protogen/gen/ocis/services/settings/v0"
)
const (
// BundleUUIDRoleAdmin represents the admin role
BundleUUIDRoleAdmin = "71881883-1768-46bd-a24d-a356a2afdf7f"
@@ -64,567 +59,3 @@ const (
// ChangeLogoPermissionName is the hardcoded setting name for the change-logo permission
ChangeLogoPermissionName string = "change-logo"
)
// generateBundlesDefaultRoles bootstraps the default roles.
func generateBundlesDefaultRoles() []*settingsmsg.Bundle {
return []*settingsmsg.Bundle{
generateBundleAdminRole(),
generateBundleSpaceAdminRole(),
generateBundleUserRole(),
generateBundleGuestRole(),
generateBundleProfileRequest(),
}
}
func generateBundleAdminRole() *settingsmsg.Bundle {
return &settingsmsg.Bundle{
Id: BundleUUIDRoleAdmin,
Name: "admin",
Type: settingsmsg.Bundle_TYPE_ROLE,
Extension: "ocis-roles",
DisplayName: "Admin",
Resource: &settingsmsg.Resource{
Type: settingsmsg.Resource_TYPE_SYSTEM,
},
Settings: []*settingsmsg.Setting{},
}
}
func generateBundleSpaceAdminRole() *settingsmsg.Bundle {
return &settingsmsg.Bundle{
Id: BundleUUIDRoleSpaceAdmin,
Name: "spaceadmin",
Type: settingsmsg.Bundle_TYPE_ROLE,
Extension: "ocis-roles",
DisplayName: "Space Admin",
Resource: &settingsmsg.Resource{
Type: settingsmsg.Resource_TYPE_SYSTEM,
},
Settings: []*settingsmsg.Setting{},
}
}
func generateBundleUserRole() *settingsmsg.Bundle {
return &settingsmsg.Bundle{
Id: BundleUUIDRoleUser,
Name: "user",
Type: settingsmsg.Bundle_TYPE_ROLE,
Extension: "ocis-roles",
DisplayName: "User",
Resource: &settingsmsg.Resource{
Type: settingsmsg.Resource_TYPE_SYSTEM,
},
Settings: []*settingsmsg.Setting{},
}
}
func generateBundleGuestRole() *settingsmsg.Bundle {
return &settingsmsg.Bundle{
Id: BundleUUIDRoleGuest,
Name: "guest",
Type: settingsmsg.Bundle_TYPE_ROLE,
Extension: "ocis-roles",
DisplayName: "Guest",
Resource: &settingsmsg.Resource{
Type: settingsmsg.Resource_TYPE_SYSTEM,
},
Settings: []*settingsmsg.Setting{},
}
}
var languageSetting = settingsmsg.Setting_SingleChoiceValue{
SingleChoiceValue: &settingsmsg.SingleChoiceList{
Options: []*settingsmsg.ListOption{
{
Value: &settingsmsg.ListOptionValue{
Option: &settingsmsg.ListOptionValue_StringValue{
StringValue: "bg",
},
},
DisplayValue: "български",
},
{
Value: &settingsmsg.ListOptionValue{
Option: &settingsmsg.ListOptionValue_StringValue{
StringValue: "cs",
},
},
DisplayValue: "Czech",
},
{
Value: &settingsmsg.ListOptionValue{
Option: &settingsmsg.ListOptionValue_StringValue{
StringValue: "de",
},
},
DisplayValue: "Deutsch",
},
{
Value: &settingsmsg.ListOptionValue{
Option: &settingsmsg.ListOptionValue_StringValue{
StringValue: "en",
},
},
DisplayValue: "English",
},
{
Value: &settingsmsg.ListOptionValue{
Option: &settingsmsg.ListOptionValue_StringValue{
StringValue: "es",
},
},
DisplayValue: "Español",
},
{
Value: &settingsmsg.ListOptionValue{
Option: &settingsmsg.ListOptionValue_StringValue{
StringValue: "fr",
},
},
DisplayValue: "Français",
},
{
Value: &settingsmsg.ListOptionValue{
Option: &settingsmsg.ListOptionValue_StringValue{
StringValue: "gl",
},
},
DisplayValue: "Galego",
},
{
Value: &settingsmsg.ListOptionValue{
Option: &settingsmsg.ListOptionValue_StringValue{
StringValue: "it",
},
},
DisplayValue: "Italiano",
},
{
Value: &settingsmsg.ListOptionValue{
Option: &settingsmsg.ListOptionValue_StringValue{
StringValue: "nl",
},
},
DisplayValue: "Nederlands",
},
{
Value: &settingsmsg.ListOptionValue{
Option: &settingsmsg.ListOptionValue_StringValue{
StringValue: "ko",
},
},
DisplayValue: "한국어",
},
{
Value: &settingsmsg.ListOptionValue{
Option: &settingsmsg.ListOptionValue_StringValue{
StringValue: "sq",
},
},
DisplayValue: "Shqipja",
},
{
Value: &settingsmsg.ListOptionValue{
Option: &settingsmsg.ListOptionValue_StringValue{
StringValue: "sv",
},
},
DisplayValue: "Svenska",
},
{
Value: &settingsmsg.ListOptionValue{
Option: &settingsmsg.ListOptionValue_StringValue{
StringValue: "tr",
},
},
DisplayValue: "Türkçe",
},
},
},
}
func generateBundleProfileRequest() *settingsmsg.Bundle {
return &settingsmsg.Bundle{
Id: "2a506de7-99bd-4f0d-994e-c38e72c28fd9",
Name: "profile",
Extension: "ocis-accounts",
Type: settingsmsg.Bundle_TYPE_DEFAULT,
Resource: &settingsmsg.Resource{
Type: settingsmsg.Resource_TYPE_SYSTEM,
},
DisplayName: "Profile",
Settings: []*settingsmsg.Setting{
{
Id: SettingUUIDProfileLanguage,
Name: "language",
DisplayName: "Language",
Description: "User language",
Resource: &settingsmsg.Resource{
Type: settingsmsg.Resource_TYPE_USER,
},
Value: &languageSetting,
},
},
}
}
func generatePermissionRequests() []*settingssvc.AddSettingToBundleRequest {
return []*settingssvc.AddSettingToBundleRequest{
{
BundleId: BundleUUIDRoleAdmin,
Setting: &settingsmsg.Setting{
Id: RoleManagementPermissionID,
Name: RoleManagementPermissionName,
DisplayName: "Role Management",
Description: "This permission gives full access to everything that is related to role management.",
Resource: &settingsmsg.Resource{
Type: settingsmsg.Resource_TYPE_USER,
Id: "all",
},
Value: &settingsmsg.Setting_PermissionValue{
PermissionValue: &settingsmsg.Permission{
Operation: settingsmsg.Permission_OPERATION_READWRITE,
Constraint: settingsmsg.Permission_CONSTRAINT_ALL,
},
},
},
},
{
BundleId: BundleUUIDRoleAdmin,
Setting: &settingsmsg.Setting{
Id: SettingsManagementPermissionID,
Name: SettingsManagementPermissionName,
DisplayName: "Settings Management",
Description: "This permission gives full access to everything that is related to settings management.",
Resource: &settingsmsg.Resource{
Type: settingsmsg.Resource_TYPE_USER,
Id: "all",
},
Value: &settingsmsg.Setting_PermissionValue{
PermissionValue: &settingsmsg.Permission{
Operation: settingsmsg.Permission_OPERATION_READWRITE,
Constraint: settingsmsg.Permission_CONSTRAINT_ALL,
},
},
},
},
{
BundleId: BundleUUIDRoleAdmin,
Setting: &settingsmsg.Setting{
Id: "7d81f103-0488-4853-bce5-98dcce36d649",
Name: "language-readwrite",
DisplayName: "Permission to read and set the language (anyone)",
Resource: &settingsmsg.Resource{
Type: settingsmsg.Resource_TYPE_SETTING,
Id: SettingUUIDProfileLanguage,
},
Value: &settingsmsg.Setting_PermissionValue{
PermissionValue: &settingsmsg.Permission{
Operation: settingsmsg.Permission_OPERATION_READWRITE,
Constraint: settingsmsg.Permission_CONSTRAINT_ALL,
},
},
},
},
{
BundleId: BundleUUIDRoleUser,
Setting: &settingsmsg.Setting{
Id: "640e00d2-4df8-41bd-b1c2-9f30a01e0e99",
Name: "language-readwrite",
DisplayName: "Permission to read and set the language (self)",
Resource: &settingsmsg.Resource{
Type: settingsmsg.Resource_TYPE_SETTING,
Id: SettingUUIDProfileLanguage,
},
Value: &settingsmsg.Setting_PermissionValue{
PermissionValue: &settingsmsg.Permission{
Operation: settingsmsg.Permission_OPERATION_READWRITE,
Constraint: settingsmsg.Permission_CONSTRAINT_OWN,
},
},
},
},
{
BundleId: BundleUUIDRoleGuest,
Setting: &settingsmsg.Setting{
Id: "ca878636-8b1a-4fae-8282-8617a4c13597",
Name: "language-readwrite",
DisplayName: "Permission to read and set the language (self)",
Resource: &settingsmsg.Resource{
Type: settingsmsg.Resource_TYPE_SETTING,
Id: SettingUUIDProfileLanguage,
},
Value: &settingsmsg.Setting_PermissionValue{
PermissionValue: &settingsmsg.Permission{
Operation: settingsmsg.Permission_OPERATION_READWRITE,
Constraint: settingsmsg.Permission_CONSTRAINT_OWN,
},
},
},
},
{
BundleId: BundleUUIDRoleAdmin,
Setting: &settingsmsg.Setting{
Id: AccountManagementPermissionID,
Name: AccountManagementPermissionName,
DisplayName: "Account Management",
Description: "This permission gives full access to everything that is related to account management.",
Resource: &settingsmsg.Resource{
Type: settingsmsg.Resource_TYPE_USER,
Id: "all",
},
Value: &settingsmsg.Setting_PermissionValue{
PermissionValue: &settingsmsg.Permission{
Operation: settingsmsg.Permission_OPERATION_READWRITE,
Constraint: settingsmsg.Permission_CONSTRAINT_ALL,
},
},
},
},
{
BundleId: BundleUUIDRoleAdmin,
Setting: &settingsmsg.Setting{
Id: GroupManagementPermissionID,
Name: GroupManagementPermissionName,
DisplayName: "Group Management",
Description: "This permission gives full access to everything that is related to group management.",
Resource: &settingsmsg.Resource{
Type: settingsmsg.Resource_TYPE_GROUP,
Id: "all",
},
Value: &settingsmsg.Setting_PermissionValue{
PermissionValue: &settingsmsg.Permission{
Operation: settingsmsg.Permission_OPERATION_READWRITE,
Constraint: settingsmsg.Permission_CONSTRAINT_ALL,
},
},
},
},
{
BundleId: BundleUUIDRoleUser,
Setting: &settingsmsg.Setting{
Id: SelfManagementPermissionID,
Name: SelfManagementPermissionName,
DisplayName: "Self Management",
Description: "This permission gives access to self management.",
Resource: &settingsmsg.Resource{
Type: settingsmsg.Resource_TYPE_USER,
Id: "me",
},
Value: &settingsmsg.Setting_PermissionValue{
PermissionValue: &settingsmsg.Permission{
Operation: settingsmsg.Permission_OPERATION_READWRITE,
Constraint: settingsmsg.Permission_CONSTRAINT_OWN,
},
},
},
},
{
BundleId: BundleUUIDRoleAdmin,
Setting: &settingsmsg.Setting{
Id: SetSpaceQuotaPermissionID,
Name: SetSpaceQuotaPermissionName,
DisplayName: "Set Space Quota",
Description: "This permission allows managing space quotas.",
Resource: &settingsmsg.Resource{
Type: settingsmsg.Resource_TYPE_SYSTEM,
},
Value: &settingsmsg.Setting_PermissionValue{
PermissionValue: &settingsmsg.Permission{
Operation: settingsmsg.Permission_OPERATION_READWRITE,
Constraint: settingsmsg.Permission_CONSTRAINT_ALL,
},
},
},
},
{
BundleId: BundleUUIDRoleUser,
Setting: &settingsmsg.Setting{
Id: CreateSpacePermissionID,
Name: CreateSpacePermissionName,
DisplayName: "Create own Space",
Description: "This permission allows creating a space owned by the current user.",
Resource: &settingsmsg.Resource{
Type: settingsmsg.Resource_TYPE_SYSTEM, // TODO resource type space? self? me? own?
},
Value: &settingsmsg.Setting_PermissionValue{
PermissionValue: &settingsmsg.Permission{
Operation: settingsmsg.Permission_OPERATION_CREATE,
Constraint: settingsmsg.Permission_CONSTRAINT_OWN,
},
},
},
},
{
BundleId: BundleUUIDRoleAdmin,
Setting: &settingsmsg.Setting{
Id: CreateSpacePermissionID,
Name: CreateSpacePermissionName,
DisplayName: "Create Space",
Description: "This permission allows creating new spaces.",
Resource: &settingsmsg.Resource{
Type: settingsmsg.Resource_TYPE_SYSTEM,
},
Value: &settingsmsg.Setting_PermissionValue{
PermissionValue: &settingsmsg.Permission{
Operation: settingsmsg.Permission_OPERATION_READWRITE,
Constraint: settingsmsg.Permission_CONSTRAINT_ALL,
},
},
},
},
{
BundleId: BundleUUIDRoleAdmin,
Setting: &settingsmsg.Setting{
Id: ListAllSpacesPermissionID,
Name: ListAllSpacesPermissionName,
DisplayName: "List All Spaces",
Description: "This permission allows list all spaces.",
Resource: &settingsmsg.Resource{
Type: settingsmsg.Resource_TYPE_SYSTEM,
},
Value: &settingsmsg.Setting_PermissionValue{
PermissionValue: &settingsmsg.Permission{
Operation: settingsmsg.Permission_OPERATION_READ,
Constraint: settingsmsg.Permission_CONSTRAINT_ALL,
},
},
},
},
{
BundleId: BundleUUIDRoleAdmin,
Setting: &settingsmsg.Setting{
Id: ChangeLogoPermissionID,
Name: ChangeLogoPermissionName,
DisplayName: "Change logo",
Description: "This permission permits to change the system logo.",
Resource: &settingsmsg.Resource{
Type: settingsmsg.Resource_TYPE_SYSTEM,
},
Value: &settingsmsg.Setting_PermissionValue{
PermissionValue: &settingsmsg.Permission{
Operation: settingsmsg.Permission_OPERATION_READWRITE,
Constraint: settingsmsg.Permission_CONSTRAINT_ALL,
},
},
},
},
{
BundleId: BundleUUIDRoleSpaceAdmin,
Setting: &settingsmsg.Setting{
Id: CreateSpacePermissionID,
Name: CreateSpacePermissionName,
DisplayName: "Create Space",
Description: "This permission allows creating new spaces.",
Resource: &settingsmsg.Resource{
Type: settingsmsg.Resource_TYPE_SYSTEM,
},
Value: &settingsmsg.Setting_PermissionValue{
PermissionValue: &settingsmsg.Permission{
Operation: settingsmsg.Permission_OPERATION_READWRITE,
Constraint: settingsmsg.Permission_CONSTRAINT_ALL,
},
},
},
},
{
BundleId: BundleUUIDRoleSpaceAdmin,
Setting: &settingsmsg.Setting{
Id: SetSpaceQuotaPermissionID,
Name: SetSpaceQuotaPermissionName,
DisplayName: "Set Space Quota",
Description: "This permission allows managing space quotas.",
Resource: &settingsmsg.Resource{
Type: settingsmsg.Resource_TYPE_SYSTEM,
},
Value: &settingsmsg.Setting_PermissionValue{
PermissionValue: &settingsmsg.Permission{
Operation: settingsmsg.Permission_OPERATION_READWRITE,
Constraint: settingsmsg.Permission_CONSTRAINT_ALL,
},
},
},
},
{
BundleId: BundleUUIDRoleSpaceAdmin,
Setting: &settingsmsg.Setting{
Id: ListAllSpacesPermissionID,
Name: ListAllSpacesPermissionName,
DisplayName: "List All Spaces",
Description: "This permission allows list all spaces.",
Resource: &settingsmsg.Resource{
Type: settingsmsg.Resource_TYPE_SYSTEM,
},
Value: &settingsmsg.Setting_PermissionValue{
PermissionValue: &settingsmsg.Permission{
Operation: settingsmsg.Permission_OPERATION_READ,
Constraint: settingsmsg.Permission_CONSTRAINT_ALL,
},
},
},
},
{
BundleId: BundleUUIDRoleSpaceAdmin,
Setting: &settingsmsg.Setting{
Id: "640e00d2-4df8-41bd-b1c2-9f30a01e0e99",
Name: "language-readwrite",
DisplayName: "Permission to read and set the language (self)",
Resource: &settingsmsg.Resource{
Type: settingsmsg.Resource_TYPE_SETTING,
Id: SettingUUIDProfileLanguage,
},
Value: &settingsmsg.Setting_PermissionValue{
PermissionValue: &settingsmsg.Permission{
Operation: settingsmsg.Permission_OPERATION_READWRITE,
Constraint: settingsmsg.Permission_CONSTRAINT_OWN,
},
},
},
},
{
BundleId: BundleUUIDRoleSpaceAdmin,
Setting: &settingsmsg.Setting{
Id: SelfManagementPermissionID,
Name: SelfManagementPermissionName,
DisplayName: "Self Management",
Description: "This permission gives access to self management.",
Resource: &settingsmsg.Resource{
Type: settingsmsg.Resource_TYPE_USER,
Id: "me",
},
Value: &settingsmsg.Setting_PermissionValue{
PermissionValue: &settingsmsg.Permission{
Operation: settingsmsg.Permission_OPERATION_READWRITE,
Constraint: settingsmsg.Permission_CONSTRAINT_OWN,
},
},
},
},
}
}
func (g Service) defaultRoleAssignments() []*settingsmsg.UserRoleAssignment {
return []*settingsmsg.UserRoleAssignment{
// default admin users
{
AccountUuid: g.config.AdminUserID,
RoleId: BundleUUIDRoleAdmin,
},
// default users with role "user"
{
AccountUuid: "4c510ada-c86b-4815-8820-42cdf82c3d51", // demo user "einstein"
RoleId: BundleUUIDRoleUser,
}, {
AccountUuid: "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c", // demo user "marie"
RoleId: BundleUUIDRoleUser,
},
// default users with role "spaceadmin"
{
AccountUuid: "058bff95-6708-4fe5-91e4-9ea3d377588b", // demo user "moss"
RoleId: BundleUUIDRoleSpaceAdmin,
}, {
AccountUuid: "534bb038-6f9d-4093-946f-133be61fa4e7", // demo user "katherine"
RoleId: BundleUUIDRoleSpaceAdmin,
},
}
}
@@ -1,66 +0,0 @@
// Package store implements the go-micro store interface
package store
import (
"os"
"path/filepath"
"github.com/gofrs/uuid"
settingsmsg "github.com/owncloud/ocis/v2/protogen/gen/ocis/messages/settings/v0"
)
// ListRoleAssignments loads and returns all role assignments matching the given assignment identifier.
func (s Store) ListRoleAssignments(accountUUID string) ([]*settingsmsg.UserRoleAssignment, error) {
var records []*settingsmsg.UserRoleAssignment
assignmentsFolder := s.buildFolderPathForRoleAssignments(false)
assignmentFiles, err := os.ReadDir(assignmentsFolder)
if err != nil {
return nil, nil
}
for _, assignmentFile := range assignmentFiles {
record := settingsmsg.UserRoleAssignment{}
err = s.parseRecordFromFile(&record, filepath.Join(assignmentsFolder, assignmentFile.Name()))
if err == nil {
if record.AccountUuid == accountUUID {
records = append(records, &record)
}
}
}
return records, nil
}
// WriteRoleAssignment appends the given role assignment to the existing assignments of the respective account.
func (s Store) WriteRoleAssignment(accountUUID, roleID string) (*settingsmsg.UserRoleAssignment, error) {
// as per https://github.com/owncloud/product/issues/103 "Each user can have exactly one role"
list, err := s.ListRoleAssignments(accountUUID)
if err != nil {
return nil, err
}
if len(list) > 0 {
filePath := s.buildFilePathForRoleAssignment(list[0].Id, true)
if err := os.Remove(filePath); err != nil {
return nil, err
}
}
assignment := &settingsmsg.UserRoleAssignment{
Id: uuid.Must(uuid.NewV4()).String(),
AccountUuid: accountUUID,
RoleId: roleID,
}
filePath := s.buildFilePathForRoleAssignment(assignment.Id, true)
if err := s.writeRecordToFile(assignment, filePath); err != nil {
return nil, err
}
s.Logger.Debug().Msgf("request contents written to file: %v", filePath)
return assignment, nil
}
// RemoveRoleAssignment deletes the given role assignment from the existing assignments of the respective account.
func (s Store) RemoveRoleAssignment(assignmentID string) error {
filePath := s.buildFilePathForRoleAssignment(assignmentID, false)
return os.Remove(filePath)
}
@@ -1,178 +0,0 @@
package store
import (
"errors"
"log"
"os"
"path/filepath"
"testing"
olog "github.com/owncloud/ocis/v2/ocis-pkg/log"
settingsmsg "github.com/owncloud/ocis/v2/protogen/gen/ocis/messages/settings/v0"
"github.com/stretchr/testify/assert"
)
var (
einstein = "a4d07560-a670-4be9-8d60-9b547751a208"
//marie = "3c054db3-eec1-4ca4-b985-bc56dcf560cb"
s = Store{
dataPath: dataRoot,
Logger: logger,
}
logger = olog.NewLogger(
olog.Color(true),
olog.Pretty(true),
olog.Level("info"),
)
bundles = []*settingsmsg.Bundle{
{
Id: "f36db5e6-a03c-40df-8413-711c67e40b47",
Type: settingsmsg.Bundle_TYPE_ROLE,
DisplayName: "test role - reads | update",
Name: "TEST_ROLE",
Extension: "ocis-settings",
Resource: &settingsmsg.Resource{
Type: settingsmsg.Resource_TYPE_BUNDLE,
},
Settings: []*settingsmsg.Setting{
{
Name: "update",
Value: &settingsmsg.Setting_PermissionValue{
PermissionValue: &settingsmsg.Permission{
Operation: settingsmsg.Permission_OPERATION_UPDATE,
},
},
},
{
Name: "read",
Value: &settingsmsg.Setting_PermissionValue{
PermissionValue: &settingsmsg.Permission{
Operation: settingsmsg.Permission_OPERATION_READ,
},
},
},
},
},
{
Id: "44f1a664-0a7f-461a-b0be-5b59e46bbc7a",
Type: settingsmsg.Bundle_TYPE_ROLE,
DisplayName: "another",
Name: "ANOTHER_TEST_ROLE",
Extension: "ocis-settings",
Resource: &settingsmsg.Resource{
Type: settingsmsg.Resource_TYPE_BUNDLE,
},
Settings: []*settingsmsg.Setting{
{
Name: "read",
Value: &settingsmsg.Setting_PermissionValue{
PermissionValue: &settingsmsg.Permission{
Operation: settingsmsg.Permission_OPERATION_READ,
},
},
},
},
},
}
)
func init() {
setupRoles()
}
func setupRoles() {
for i := range bundles {
if _, err := s.WriteBundle(bundles[i]); err != nil {
log.Fatal(err)
}
}
}
func TestAssignmentUniqueness(t *testing.T) {
var scenarios = []struct {
name string
userID string
firstRole string
secondRole string
}{
{
"roles assignments",
einstein,
"f36db5e6-a03c-40df-8413-711c67e40b47",
"44f1a664-0a7f-461a-b0be-5b59e46bbc7a",
},
}
for _, scenario := range scenarios {
scenario := scenario
t.Run(scenario.name, func(t *testing.T) {
firstAssignment, err := s.WriteRoleAssignment(scenario.userID, scenario.firstRole)
assert.NoError(t, err)
assert.Equal(t, firstAssignment.RoleId, scenario.firstRole)
assert.FileExists(t, filepath.Join(dataRoot, "assignments", firstAssignment.Id+".json"))
list, err := s.ListRoleAssignments(scenario.userID)
assert.NoError(t, err)
assert.Equal(t, 1, len(list))
// creating another assignment shouldn't add another entry, as we support max one role per user.
secondAssignment, err := s.WriteRoleAssignment(scenario.userID, scenario.secondRole)
assert.NoError(t, err)
assert.Equal(t, 1, len(list))
// assigning the second role should remove the old file and create a new one.
list, err = s.ListRoleAssignments(scenario.userID)
assert.NoError(t, err)
assert.Equal(t, 1, len(list))
assert.Equal(t, secondAssignment.RoleId, scenario.secondRole)
assert.NoFileExists(t, filepath.Join(dataRoot, "assignments", firstAssignment.Id+".json"))
assert.FileExists(t, filepath.Join(dataRoot, "assignments", secondAssignment.Id+".json"))
})
}
burnRoot()
}
func TestDeleteAssignment(t *testing.T) {
var scenarios = []struct {
name string
userID string
firstRole string
secondRole string
}{
{
"roles assignments",
einstein,
"f36db5e6-a03c-40df-8413-711c67e40b47",
"44f1a664-0a7f-461a-b0be-5b59e46bbc7a",
},
}
for _, scenario := range scenarios {
scenario := scenario
t.Run(scenario.name, func(t *testing.T) {
assignment, err := s.WriteRoleAssignment(scenario.userID, scenario.firstRole)
assert.NoError(t, err)
assert.Equal(t, assignment.RoleId, scenario.firstRole)
assert.FileExists(t, filepath.Join(dataRoot, "assignments", assignment.Id+".json"))
list, err := s.ListRoleAssignments(scenario.userID)
assert.NoError(t, err)
assert.Equal(t, 1, len(list))
err = s.RemoveRoleAssignment(assignment.Id)
assert.NoError(t, err)
list, err = s.ListRoleAssignments(scenario.userID)
assert.NoError(t, err)
assert.Equal(t, 0, len(list))
err = s.RemoveRoleAssignment(assignment.Id)
merr := &os.PathError{}
assert.Equal(t, true, errors.As(err, &merr))
})
}
burnRoot()
}
@@ -1,181 +0,0 @@
// Package store implements the go-micro store interface
package store
import (
"errors"
"fmt"
"os"
"path/filepath"
"sync"
"github.com/gofrs/uuid"
settingsmsg "github.com/owncloud/ocis/v2/protogen/gen/ocis/messages/settings/v0"
"github.com/owncloud/ocis/v2/services/settings/pkg/settings"
)
var m = &sync.RWMutex{}
// ListBundles returns all bundles in the dataPath folder that match the given type.
func (s Store) ListBundles(bundleType settingsmsg.Bundle_Type, bundleIDs []string) ([]*settingsmsg.Bundle, error) {
// FIXME: list requests should be ran against a cache, not FS
m.RLock()
defer m.RUnlock()
bundlesFolder := s.buildFolderPathForBundles(false)
bundleFiles, err := os.ReadDir(bundlesFolder)
if err != nil {
return nil, err
}
records := make([]*settingsmsg.Bundle, 0, len(bundleFiles))
for _, bundleFile := range bundleFiles {
record := settingsmsg.Bundle{}
err = s.parseRecordFromFile(&record, filepath.Join(bundlesFolder, bundleFile.Name()))
if err != nil {
s.Logger.Warn().Msgf("error reading %v", bundleFile)
continue
}
if record.Type != bundleType {
continue
}
if len(bundleIDs) > 0 && !containsStr(record.Id, bundleIDs) {
continue
}
records = append(records, &record)
}
return records, nil
}
// containsStr checks if the strs slice contains str
func containsStr(str string, strs []string) bool {
for _, s := range strs {
if s == str {
return true
}
}
return false
}
// ReadBundle tries to find a bundle by the given id within the dataPath.
func (s Store) ReadBundle(bundleID string) (*settingsmsg.Bundle, error) {
m.RLock()
defer m.RUnlock()
filePath := s.buildFilePathForBundle(bundleID, false)
record := settingsmsg.Bundle{}
if err := s.parseRecordFromFile(&record, filePath); err != nil {
return nil, err
}
s.Logger.Debug().Msgf("read contents from file: %v", filePath)
return &record, nil
}
// ReadSetting tries to find a setting by the given id within the dataPath.
func (s Store) ReadSetting(settingID string) (*settingsmsg.Setting, error) {
m.RLock()
defer m.RUnlock()
bundles, err := s.ListBundles(settingsmsg.Bundle_TYPE_DEFAULT, []string{})
if err != nil {
return nil, err
}
for _, bundle := range bundles {
for _, setting := range bundle.Settings {
if setting.Id == settingID {
return setting, nil
}
}
}
return nil, fmt.Errorf("could not read setting: %v", settingID)
}
// WriteBundle writes the given record into a file within the dataPath.
func (s Store) WriteBundle(record *settingsmsg.Bundle) (*settingsmsg.Bundle, error) {
// FIXME: locking should happen on the file here, not globally.
m.Lock()
defer m.Unlock()
if record.Id == "" {
record.Id = uuid.Must(uuid.NewV4()).String()
}
filePath := s.buildFilePathForBundle(record.Id, true)
if err := s.writeRecordToFile(record, filePath); err != nil {
return nil, err
}
s.Logger.Debug().Msgf("request contents written to file: %v", filePath)
return record, nil
}
// AddSettingToBundle adds the given setting to the bundle with the given bundleID.
func (s Store) AddSettingToBundle(bundleID string, setting *settingsmsg.Setting) (*settingsmsg.Setting, error) {
bundle, err := s.ReadBundle(bundleID)
if err != nil {
if !errors.Is(err, settings.ErrNotFound) {
return nil, err
}
bundle = new(settingsmsg.Bundle)
bundle.Id = bundleID
bundle.Type = settingsmsg.Bundle_TYPE_DEFAULT
}
if setting.Id == "" {
setting.Id = uuid.Must(uuid.NewV4()).String()
}
setSetting(bundle, setting)
_, err = s.WriteBundle(bundle)
if err != nil {
return nil, err
}
return setting, nil
}
// RemoveSettingFromBundle removes the setting from the bundle with the given ids.
func (s Store) RemoveSettingFromBundle(bundleID string, settingID string) error {
bundle, err := s.ReadBundle(bundleID)
if err != nil {
return err
}
if ok := removeSetting(bundle, settingID); ok {
if _, err := s.WriteBundle(bundle); err != nil {
return err
}
}
return nil
}
// indexOfSetting finds the index of the given setting within the given bundle.
// returns -1 if the setting was not found.
func indexOfSetting(bundle *settingsmsg.Bundle, settingID string) int {
for index := range bundle.Settings {
s := bundle.Settings[index]
if s.Id == settingID {
return index
}
}
return -1
}
// setSetting will append or overwrite the given setting within the given bundle
func setSetting(bundle *settingsmsg.Bundle, setting *settingsmsg.Setting) {
m.Lock()
defer m.Unlock()
index := indexOfSetting(bundle, setting.Id)
if index == -1 {
bundle.Settings = append(bundle.Settings, setting)
} else {
bundle.Settings[index] = setting
}
}
// removeSetting will remove the given setting from the given bundle
func removeSetting(bundle *settingsmsg.Bundle, settingID string) bool {
m.Lock()
defer m.Unlock()
index := indexOfSetting(bundle, settingID)
if index == -1 {
return false
}
bundle.Settings = append(bundle.Settings[:index], bundle.Settings[index+1:]...)
return true
}
@@ -1,155 +0,0 @@
package store
import (
"testing"
olog "github.com/owncloud/ocis/v2/ocis-pkg/log"
settingsmsg "github.com/owncloud/ocis/v2/protogen/gen/ocis/messages/settings/v0"
"github.com/stretchr/testify/assert"
)
var bundleScenarios = []struct {
name string
bundle *settingsmsg.Bundle
}{
{
name: "generic-test-file-resource",
bundle: &settingsmsg.Bundle{
Id: bundle1,
Type: settingsmsg.Bundle_TYPE_DEFAULT,
Extension: extension1,
DisplayName: "test1",
Resource: &settingsmsg.Resource{
Type: settingsmsg.Resource_TYPE_FILE,
Id: "beep",
},
Settings: []*settingsmsg.Setting{
{
Id: setting1,
Description: "test-desc-1",
DisplayName: "test-displayname-1",
Resource: &settingsmsg.Resource{
Type: settingsmsg.Resource_TYPE_FILE,
Id: "bleep",
},
Value: &settingsmsg.Setting_IntValue{
IntValue: &settingsmsg.Int{
Min: 0,
Max: 42,
},
},
},
},
},
},
{
name: "generic-test-system-resource",
bundle: &settingsmsg.Bundle{
Id: bundle2,
Type: settingsmsg.Bundle_TYPE_DEFAULT,
Extension: extension2,
DisplayName: "test1",
Resource: &settingsmsg.Resource{
Type: settingsmsg.Resource_TYPE_SYSTEM,
},
Settings: []*settingsmsg.Setting{
{
Id: setting2,
Description: "test-desc-2",
DisplayName: "test-displayname-2",
Resource: &settingsmsg.Resource{
Type: settingsmsg.Resource_TYPE_SYSTEM,
},
Value: &settingsmsg.Setting_IntValue{
IntValue: &settingsmsg.Int{
Min: 0,
Max: 42,
},
},
},
},
},
},
{
name: "generic-test-role-bundle",
bundle: &settingsmsg.Bundle{
Id: bundle3,
Type: settingsmsg.Bundle_TYPE_ROLE,
Extension: extension1,
DisplayName: "Role1",
Resource: &settingsmsg.Resource{
Type: settingsmsg.Resource_TYPE_SYSTEM,
},
Settings: []*settingsmsg.Setting{
{
Id: setting3,
Description: "test-desc-3",
DisplayName: "test-displayname-3",
Resource: &settingsmsg.Resource{
Type: settingsmsg.Resource_TYPE_SETTING,
Id: setting1,
},
Value: &settingsmsg.Setting_PermissionValue{
PermissionValue: &settingsmsg.Permission{
Operation: settingsmsg.Permission_OPERATION_READ,
Constraint: settingsmsg.Permission_CONSTRAINT_OWN,
},
},
},
},
},
},
}
func TestBundles(t *testing.T) {
s := Store{
dataPath: dataRoot,
Logger: olog.NewLogger(
olog.Color(true),
olog.Pretty(true),
olog.Level("info"),
),
}
// write bundles
for i := range bundleScenarios {
index := i
t.Run(bundleScenarios[index].name, func(t *testing.T) {
filePath := s.buildFilePathForBundle(bundleScenarios[index].bundle.Id, true)
if err := s.writeRecordToFile(bundleScenarios[index].bundle, filePath); err != nil {
t.Error(err)
}
assert.FileExists(t, filePath)
})
}
// check that ListBundles only returns bundles with type DEFAULT
bundles, err := s.ListBundles(settingsmsg.Bundle_TYPE_DEFAULT, []string{})
if err != nil {
t.Error(err)
}
for i := range bundles {
assert.Equal(t, settingsmsg.Bundle_TYPE_DEFAULT, bundles[i].Type)
}
// check that ListBundles filtered by an id only returns that bundle
filteredBundles, err := s.ListBundles(settingsmsg.Bundle_TYPE_DEFAULT, []string{bundle2})
if err != nil {
t.Error(err)
}
assert.Equal(t, 1, len(filteredBundles))
if len(filteredBundles) == 1 {
assert.Equal(t, bundle2, filteredBundles[0].Id)
}
// check that ListRoles only returns bundles with type ROLE
roles, err := s.ListBundles(settingsmsg.Bundle_TYPE_ROLE, []string{})
if err != nil {
t.Error(err)
}
for i := range roles {
assert.Equal(t, settingsmsg.Bundle_TYPE_ROLE, roles[i].Type)
}
burnRoot()
}
@@ -1,60 +0,0 @@
package store
import (
"fmt"
"io"
"os"
"github.com/owncloud/ocis/v2/services/settings/pkg/settings"
"google.golang.org/protobuf/encoding/protojson"
"google.golang.org/protobuf/proto"
)
// Unmarshal file into record
func (s Store) parseRecordFromFile(record proto.Message, filePath string) error {
_, err := os.Stat(filePath)
if err != nil {
return fmt.Errorf("%q: %w", filePath, settings.ErrNotFound)
}
file, err := os.Open(filePath)
if err != nil {
return err
}
defer file.Close()
b, err := io.ReadAll(file)
if err != nil {
return err
}
if len(b) == 0 {
return fmt.Errorf("%q: %w", filePath, settings.ErrNotFound)
}
if err := protojson.Unmarshal(b, record); err != nil {
return err
}
return nil
}
// Marshal record into file
func (s Store) writeRecordToFile(record proto.Message, filePath string) error {
file, err := os.Create(filePath)
if err != nil {
return err
}
defer file.Close()
v, err := protojson.Marshal(record)
if err != nil {
return err
}
_, err = file.Write(v)
if err != nil {
return err
}
return nil
}
@@ -1,65 +0,0 @@
package store
import (
"os"
"path/filepath"
)
const folderNameBundles = "bundles"
const folderNameValues = "values"
const folderNameAssignments = "assignments"
// buildFolderPathForBundles builds the folder path for storing settings bundles. If mkdir is true, folders in the path will be created if necessary.
func (s Store) buildFolderPathForBundles(mkdir bool) string {
folderPath := filepath.Join(s.dataPath, folderNameBundles)
if mkdir {
s.ensureFolderExists(folderPath)
}
return folderPath
}
// buildFilePathForBundle builds a unique file name from the given params. If mkdir is true, folders in the path will be created if necessary.
func (s Store) buildFilePathForBundle(bundleID string, mkdir bool) string {
extensionFolder := s.buildFolderPathForBundles(mkdir)
return filepath.Join(extensionFolder, bundleID+".json")
}
// buildFolderPathForValues builds the folder path for storing settings values. If mkdir is true, folders in the path will be created if necessary.
func (s Store) buildFolderPathForValues(mkdir bool) string {
folderPath := filepath.Join(s.dataPath, folderNameValues)
if mkdir {
s.ensureFolderExists(folderPath)
}
return folderPath
}
// buildFilePathForValue builds a unique file name from the given params. If mkdir is true, folders in the path will be created if necessary.
func (s Store) buildFilePathForValue(valueID string, mkdir bool) string {
extensionFolder := s.buildFolderPathForValues(mkdir)
return filepath.Join(extensionFolder, valueID+".json")
}
// buildFolderPathForRoleAssignments builds the folder path for storing role assignments. If mkdir is true, folders in the path will be created if necessary.
func (s Store) buildFolderPathForRoleAssignments(mkdir bool) string {
roleAssignmentsFolder := filepath.Join(s.dataPath, folderNameAssignments)
if mkdir {
s.ensureFolderExists(roleAssignmentsFolder)
}
return roleAssignmentsFolder
}
// buildFilePathForRoleAssignment builds a unique file name from the given params. If mkdir is true, folders in the path will be created if necessary.
func (s Store) buildFilePathForRoleAssignment(assignmentID string, mkdir bool) string {
roleAssignmentsFolder := s.buildFolderPathForRoleAssignments(mkdir)
return filepath.Join(roleAssignmentsFolder, assignmentID+".json")
}
// ensureFolderExists checks if the given path is an existing folder and creates one if not existing
func (s Store) ensureFolderExists(path string) {
if _, err := os.Stat(path); os.IsNotExist(err) {
err = os.MkdirAll(path, 0700)
if err != nil {
s.Logger.Err(err).Msgf("Error creating folder %v", path)
}
}
}
@@ -1,72 +0,0 @@
package store
import (
settingsmsg "github.com/owncloud/ocis/v2/protogen/gen/ocis/messages/settings/v0"
"github.com/owncloud/ocis/v2/services/settings/pkg/settings"
"github.com/owncloud/ocis/v2/services/settings/pkg/util"
)
// ListPermissionsByResource collects all permissions from the provided roleIDs that match the requested resource
func (s Store) ListPermissionsByResource(resource *settingsmsg.Resource, roleIDs []string) ([]*settingsmsg.Permission, error) {
records := make([]*settingsmsg.Permission, 0)
for _, roleID := range roleIDs {
role, err := s.ReadBundle(roleID)
if err != nil {
s.Logger.Debug().Str("roleID", roleID).Msg("role not found, skipping")
continue
}
records = append(records, extractPermissionsByResource(resource, role)...)
}
return records, nil
}
// ReadPermissionByID finds the permission in the roles, specified by the provided roleIDs
func (s Store) ReadPermissionByID(permissionID string, roleIDs []string) (*settingsmsg.Permission, error) {
for _, roleID := range roleIDs {
role, err := s.ReadBundle(roleID)
if err != nil {
s.Logger.Debug().Str("roleID", roleID).Msg("role not found, skipping")
continue
}
for _, permission := range role.Settings {
if permission.Id == permissionID {
if value, ok := permission.Value.(*settingsmsg.Setting_PermissionValue); ok {
return value.PermissionValue, nil
}
}
}
}
return nil, nil
}
// ReadPermissionByName finds the permission in the roles, specified by the provided roleIDs
func (s Store) ReadPermissionByName(name string, roleIDs []string) (*settingsmsg.Permission, error) {
for _, roleID := range roleIDs {
role, err := s.ReadBundle(roleID)
if err != nil {
s.Logger.Debug().Str("roleID", roleID).Msg("role not found, skipping")
continue
}
for _, permission := range role.Settings {
if permission.Name == name {
if value, ok := permission.Value.(*settingsmsg.Setting_PermissionValue); ok {
return value.PermissionValue, nil
}
}
}
}
return nil, settings.ErrNotFound
}
// extractPermissionsByResource collects all permissions from the provided role that match the requested resource
func extractPermissionsByResource(resource *settingsmsg.Resource, role *settingsmsg.Bundle) []*settingsmsg.Permission {
permissions := make([]*settingsmsg.Permission, 0)
for _, setting := range role.Settings {
if value, ok := setting.Value.(*settingsmsg.Setting_PermissionValue); ok {
if util.IsResourceMatched(setting.Resource, resource) {
permissions = append(permissions, value.PermissionValue)
}
}
}
return permissions
}
@@ -1 +0,0 @@
checks = ["all", "-ST1003", "-ST1000", "-SA1019"]
@@ -1,50 +0,0 @@
// Package store implements the go-micro store interface
package store
import (
"os"
olog "github.com/owncloud/ocis/v2/ocis-pkg/log"
"github.com/owncloud/ocis/v2/services/settings/pkg/config"
"github.com/owncloud/ocis/v2/services/settings/pkg/settings"
)
var (
// Name is the default name for the settings store
Name = "ocis-settings"
managerName = "filesystem"
)
// Store interacts with the filesystem to manage settings information
type Store struct {
dataPath string
Logger olog.Logger
}
// New creates a new store
func New(cfg *config.Config) settings.Manager {
s := Store{
//Logger: olog.NewLogger(
// olog.Color(cfg.Log.Color),
// olog.Pretty(cfg.Log.Pretty),
// olog.Level(cfg.Log.Level),
// olog.File(cfg.Log.File),
//),
}
if _, err := os.Stat(cfg.DataPath); err != nil {
s.Logger.Info().Msgf("creating container on %v", cfg.DataPath)
err = os.MkdirAll(cfg.DataPath, 0700)
if err != nil {
s.Logger.Err(err).Msgf("providing container on %v", cfg.DataPath)
}
}
s.dataPath = cfg.DataPath
return &s
}
func init() {
settings.Registry[managerName] = New
}
@@ -1,39 +0,0 @@
package store
import (
"os"
"path/filepath"
)
const (
// account UUIDs
accountUUID1 = "c4572da7-6142-4383-8fc6-efde3d463036"
//accountUUID2 = "e11f9769-416a-427d-9441-41a0e51391d7"
//accountUUID3 = "633ecd77-1980-412a-8721-bf598a330bb4"
// extension names
extension1 = "test-extension-1"
extension2 = "test-extension-2"
// bundle ids
bundle1 = "2f06addf-4fd2-49d5-8f71-00fbd3a3ec47"
bundle2 = "2d745744-749c-4286-8e92-74a24d8331c5"
bundle3 = "d8fd27d1-c00b-4794-a658-416b756a72ff"
// setting ids
setting1 = "c7ebbc8b-d15a-4f2e-9d7d-d6a4cf858d1a"
setting2 = "3fd9a3d9-20b7-40d4-9294-b22bb5868c10"
setting3 = "24bb9535-3df4-42f1-a622-7c0562bec99f"
// value ids
value1 = "fd3b6221-dc13-4a22-824d-2480495f1cdb"
value2 = "2a0bd9b0-ca1d-491a-8c56-d2ddfd68ded8"
//value3 = "b42702d2-5e4d-4d73-b133-e1f9e285355e"
dataRoot = "/tmp/herecomesthesun"
)
func burnRoot() {
os.RemoveAll(filepath.Join(dataRoot, "values"))
os.RemoveAll(filepath.Join(dataRoot, "bundles"))
}
@@ -1,109 +0,0 @@
// Package store implements the go-micro store interface
package store
import (
"fmt"
"os"
"path/filepath"
"github.com/gofrs/uuid"
settingsmsg "github.com/owncloud/ocis/v2/protogen/gen/ocis/messages/settings/v0"
)
// ListValues reads all values that match the given bundleId and accountUUID.
// If the bundleId is empty, it's ignored for filtering.
// If the accountUUID is empty, only values with empty accountUUID are returned.
// If the accountUUID is not empty, values with an empty or with a matching accountUUID are returned.
func (s Store) ListValues(bundleID, accountUUID string) ([]*settingsmsg.Value, error) {
valuesFolder := s.buildFolderPathForValues(false)
valueFiles, err := os.ReadDir(valuesFolder)
if err != nil {
return nil, err
}
records := make([]*settingsmsg.Value, 0, len(valueFiles))
for _, valueFile := range valueFiles {
record := settingsmsg.Value{}
err := s.parseRecordFromFile(&record, filepath.Join(valuesFolder, valueFile.Name()))
if err != nil {
s.Logger.Warn().Msgf("error reading %v", valueFile)
continue
}
if bundleID != "" && record.BundleId != bundleID {
continue
}
// if requested accountUUID empty -> fetch all system level values
if accountUUID == "" && record.AccountUuid != "" {
continue
}
// if requested accountUUID empty -> fetch all individual + all system level values
if accountUUID != "" && record.AccountUuid != "" && record.AccountUuid != accountUUID {
continue
}
records = append(records, &record)
}
return records, nil
}
// ReadValue tries to find a value by the given valueId within the dataPath
func (s Store) ReadValue(valueID string) (*settingsmsg.Value, error) {
filePath := s.buildFilePathForValue(valueID, false)
record := settingsmsg.Value{}
if err := s.parseRecordFromFile(&record, filePath); err != nil {
return nil, err
}
s.Logger.Debug().Msgf("read contents from file: %v", filePath)
return &record, nil
}
// ReadValueByUniqueIdentifiers tries to find a value given a set of unique identifiers
func (s Store) ReadValueByUniqueIdentifiers(accountUUID, settingID string) (*settingsmsg.Value, error) {
valuesFolder := s.buildFolderPathForValues(false)
files, err := os.ReadDir(valuesFolder)
if err != nil {
return nil, err
}
for i := range files {
if !files[i].IsDir() {
r := settingsmsg.Value{}
s.Logger.Debug().Msgf("reading contents from file: %v", filepath.Join(valuesFolder, files[i].Name()))
if err := s.parseRecordFromFile(&r, filepath.Join(valuesFolder, files[i].Name())); err != nil {
s.Logger.Debug().Msgf("match found: %v", filepath.Join(valuesFolder, files[i].Name()))
return nil, err
}
// if value saved without accountUUID, then it's a global value
if r.AccountUuid == "" && r.SettingId == settingID {
return &r, nil
}
// if value saved with accountUUID, then it's a user specific value
if r.AccountUuid == accountUUID && r.SettingId == settingID {
return &r, nil
}
}
}
return nil, fmt.Errorf("could not read value by settingID=%v and accountID=%v", settingID, accountUUID)
}
// WriteValue writes the given value into a file within the dataPath
func (s Store) WriteValue(value *settingsmsg.Value) (*settingsmsg.Value, error) {
s.Logger.Debug().Str("value", value.String()).Msg("writing value")
if value.Id == "" {
value.Id = uuid.Must(uuid.NewV4()).String()
}
// modify value depending on associated resource
if value.Resource.Type == settingsmsg.Resource_TYPE_SYSTEM {
value.AccountUuid = ""
}
// write the value
filePath := s.buildFilePathForValue(value.Id, true)
if err := s.writeRecordToFile(value, filePath); err != nil {
return nil, err
}
return value, nil
}
@@ -1,70 +0,0 @@
package store
import (
"testing"
olog "github.com/owncloud/ocis/v2/ocis-pkg/log"
settingsmsg "github.com/owncloud/ocis/v2/protogen/gen/ocis/messages/settings/v0"
"github.com/stretchr/testify/assert"
)
var valueScenarios = []struct {
name string
value *settingsmsg.Value
}{
{
name: "generic-test-with-system-resource",
value: &settingsmsg.Value{
Id: value1,
BundleId: bundle1,
SettingId: setting1,
AccountUuid: accountUUID1,
Resource: &settingsmsg.Resource{
Type: settingsmsg.Resource_TYPE_SYSTEM,
},
Value: &settingsmsg.Value_StringValue{
StringValue: "lalala",
},
},
},
{
name: "generic-test-with-file-resource",
value: &settingsmsg.Value{
Id: value2,
BundleId: bundle1,
SettingId: setting2,
AccountUuid: accountUUID1,
Resource: &settingsmsg.Resource{
Type: settingsmsg.Resource_TYPE_FILE,
Id: "adfba82d-919a-41c3-9cd1-5a3f83b2bf76",
},
Value: &settingsmsg.Value_StringValue{
StringValue: "tralala",
},
},
},
}
func TestValues(t *testing.T) {
s := Store{
dataPath: dataRoot,
Logger: olog.NewLogger(
olog.Color(true),
olog.Pretty(true),
olog.Level("info"),
),
}
for i := range valueScenarios {
index := i
t.Run(valueScenarios[index].name, func(t *testing.T) {
filePath := s.buildFilePathForValue(valueScenarios[index].value.Id, true)
if err := s.writeRecordToFile(valueScenarios[index].value, filePath); err != nil {
t.Error(err)
}
assert.FileExists(t, filePath)
})
}
burnRoot()
}
-1
View File
@@ -2,6 +2,5 @@ package store
import (
// init filesystem store
_ "github.com/owncloud/ocis/v2/services/settings/pkg/store/filesystem"
_ "github.com/owncloud/ocis/v2/services/settings/pkg/store/metadata"
)