2019-05-03 10:47:22 +00:00
// Copyright 2019 Sorint.lab
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied
// See the License for the specific language governing permissions and
// limitations under the License.
2019-05-03 21:35:25 +00:00
package action
2019-05-03 10:47:22 +00:00
import (
"context"
"encoding/json"
"time"
2019-07-01 09:40:20 +00:00
"agola.io/agola/internal/datamanager"
"agola.io/agola/internal/db"
"agola.io/agola/internal/services/configstore/readdb"
"agola.io/agola/internal/util"
2019-07-31 13:39:07 +00:00
"agola.io/agola/services/configstore/types"
2019-05-03 10:47:22 +00:00
2022-02-21 08:40:18 +00:00
"github.com/gofrs/uuid"
2019-05-23 09:23:14 +00:00
errors "golang.org/x/xerrors"
2019-05-03 10:47:22 +00:00
)
type CreateUserRequest struct {
UserName string
CreateUserLARequest * CreateUserLARequest
}
2019-05-03 21:35:25 +00:00
func ( h * ActionHandler ) CreateUser ( ctx context . Context , req * CreateUserRequest ) ( * types . User , error ) {
2019-05-03 10:47:22 +00:00
if req . UserName == "" {
2022-02-21 11:19:55 +00:00
return nil , util . NewAPIError ( util . ErrBadRequest , errors . Errorf ( "user name required" ) )
2019-05-03 10:47:22 +00:00
}
if ! util . ValidateName ( req . UserName ) {
2022-02-21 11:19:55 +00:00
return nil , util . NewAPIError ( util . ErrBadRequest , errors . Errorf ( "invalid user name %q" , req . UserName ) )
2019-05-03 10:47:22 +00:00
}
var cgt * datamanager . ChangeGroupsUpdateToken
// changegroup is the username (and in future the email) to ensure no
// concurrent user creation/modification using the same name
cgNames := [ ] string { util . EncodeSha256Hex ( "username-" + req . UserName ) }
var rs * types . RemoteSource
// must do all the checks in a single transaction to avoid concurrent changes
2019-07-25 08:46:02 +00:00
err := h . readDB . Do ( ctx , func ( tx * db . Tx ) error {
2019-05-03 10:47:22 +00:00
var err error
2019-05-03 21:35:25 +00:00
cgt , err = h . readDB . GetChangeGroupsUpdateTokens ( tx , cgNames )
2019-05-03 10:47:22 +00:00
if err != nil {
return err
}
// check duplicate user name
2019-05-03 21:35:25 +00:00
u , err := h . readDB . GetUserByName ( tx , req . UserName )
2019-05-03 10:47:22 +00:00
if err != nil {
return err
}
if u != nil {
2022-02-21 11:19:55 +00:00
return util . NewAPIError ( util . ErrBadRequest , errors . Errorf ( "user with name %q already exists" , u . Name ) )
2019-05-03 10:47:22 +00:00
}
if req . CreateUserLARequest != nil {
2019-05-03 21:35:25 +00:00
rs , err = h . readDB . GetRemoteSourceByName ( tx , req . CreateUserLARequest . RemoteSourceName )
2019-05-03 10:47:22 +00:00
if err != nil {
return err
}
if rs == nil {
2022-02-21 11:19:55 +00:00
return util . NewAPIError ( util . ErrBadRequest , errors . Errorf ( "remote source %q doesn't exist" , req . CreateUserLARequest . RemoteSourceName ) )
2019-05-03 10:47:22 +00:00
}
2019-05-03 21:35:25 +00:00
user , err := h . readDB . GetUserByLinkedAccountRemoteUserIDandSource ( tx , req . CreateUserLARequest . RemoteUserID , rs . ID )
2019-05-03 10:47:22 +00:00
if err != nil {
2019-05-23 09:23:14 +00:00
return errors . Errorf ( "failed to get user for remote user id %q and remote source %q: %w" , req . CreateUserLARequest . RemoteUserID , rs . ID , err )
2019-05-03 10:47:22 +00:00
}
if user != nil {
2022-02-21 11:19:55 +00:00
return util . NewAPIError ( util . ErrBadRequest , errors . Errorf ( "user for remote user id %q for remote source %q already exists" , req . CreateUserLARequest . RemoteUserID , req . CreateUserLARequest . RemoteSourceName ) )
2019-05-03 10:47:22 +00:00
}
}
return nil
} )
if err != nil {
return nil , err
}
user := & types . User {
2022-02-21 08:40:18 +00:00
ID : uuid . Must ( uuid . NewV4 ( ) ) . String ( ) ,
2019-05-07 15:16:42 +00:00
Name : req . UserName ,
2022-02-21 08:40:18 +00:00
Secret : util . EncodeSha1Hex ( uuid . Must ( uuid . NewV4 ( ) ) . String ( ) ) ,
2019-05-03 10:47:22 +00:00
}
if req . CreateUserLARequest != nil {
if user . LinkedAccounts == nil {
user . LinkedAccounts = make ( map [ string ] * types . LinkedAccount )
}
la := & types . LinkedAccount {
2022-02-21 08:40:18 +00:00
ID : uuid . Must ( uuid . NewV4 ( ) ) . String ( ) ,
2019-05-03 10:47:22 +00:00
RemoteSourceID : rs . ID ,
RemoteUserID : req . CreateUserLARequest . RemoteUserID ,
RemoteUserName : req . CreateUserLARequest . RemoteUserName ,
UserAccessToken : req . CreateUserLARequest . UserAccessToken ,
Oauth2AccessToken : req . CreateUserLARequest . Oauth2AccessToken ,
Oauth2RefreshToken : req . CreateUserLARequest . Oauth2RefreshToken ,
Oauth2AccessTokenExpiresAt : req . CreateUserLARequest . Oauth2AccessTokenExpiresAt ,
}
user . LinkedAccounts [ la . ID ] = la
}
userj , err := json . Marshal ( user )
if err != nil {
2019-05-23 09:23:14 +00:00
return nil , errors . Errorf ( "failed to marshal user: %w" , err )
2019-05-03 10:47:22 +00:00
}
2019-05-14 08:56:17 +00:00
// create root user project group
2019-05-03 10:47:22 +00:00
pg := & types . ProjectGroup {
2022-02-21 08:40:18 +00:00
ID : uuid . Must ( uuid . NewV4 ( ) ) . String ( ) ,
2019-05-14 08:56:17 +00:00
// use public visibility
Visibility : types . VisibilityPublic ,
2019-05-03 10:47:22 +00:00
Parent : types . Parent {
Type : types . ConfigTypeUser ,
ID : user . ID ,
} ,
}
pgj , err := json . Marshal ( pg )
if err != nil {
2019-05-23 09:23:14 +00:00
return nil , errors . Errorf ( "failed to marshal project group: %w" , err )
2019-05-03 10:47:22 +00:00
}
actions := [ ] * datamanager . Action {
{
ActionType : datamanager . ActionTypePut ,
DataType : string ( types . ConfigTypeUser ) ,
ID : user . ID ,
Data : userj ,
} ,
{
ActionType : datamanager . ActionTypePut ,
DataType : string ( types . ConfigTypeProjectGroup ) ,
ID : pg . ID ,
Data : pgj ,
} ,
}
2019-05-03 21:35:25 +00:00
_ , err = h . dm . WriteWal ( ctx , actions , cgt )
2019-05-03 10:47:22 +00:00
return user , err
}
2019-05-03 21:35:25 +00:00
func ( h * ActionHandler ) DeleteUser ( ctx context . Context , userRef string ) error {
2019-05-03 10:47:22 +00:00
var user * types . User
var cgt * datamanager . ChangeGroupsUpdateToken
// must do all the checks in a single transaction to avoid concurrent changes
2019-07-25 08:46:02 +00:00
err := h . readDB . Do ( ctx , func ( tx * db . Tx ) error {
2019-05-03 10:47:22 +00:00
var err error
// check user existance
2019-05-03 21:35:25 +00:00
user , err = h . readDB . GetUser ( tx , userRef )
2019-05-03 10:47:22 +00:00
if err != nil {
return err
}
if user == nil {
2022-02-21 11:19:55 +00:00
return util . NewAPIError ( util . ErrBadRequest , errors . Errorf ( "user %q doesn't exist" , userRef ) )
2019-05-03 10:47:22 +00:00
}
// changegroup is the userid
cgNames := [ ] string { util . EncodeSha256Hex ( "userid-" + user . ID ) }
2019-05-03 21:35:25 +00:00
cgt , err = h . readDB . GetChangeGroupsUpdateTokens ( tx , cgNames )
2019-05-03 10:47:22 +00:00
if err != nil {
return err
}
return nil
} )
if err != nil {
return err
}
actions := [ ] * datamanager . Action {
{
ActionType : datamanager . ActionTypeDelete ,
DataType : string ( types . ConfigTypeUser ) ,
ID : user . ID ,
} ,
}
2019-05-03 21:35:25 +00:00
_ , err = h . dm . WriteWal ( ctx , actions , cgt )
2019-05-03 10:47:22 +00:00
return err
}
type UpdateUserRequest struct {
UserRef string
UserName string
}
2019-05-03 21:35:25 +00:00
func ( h * ActionHandler ) UpdateUser ( ctx context . Context , req * UpdateUserRequest ) ( * types . User , error ) {
2019-05-03 10:47:22 +00:00
var cgt * datamanager . ChangeGroupsUpdateToken
cgNames := [ ] string { }
var user * types . User
// must do all the checks in a single transaction to avoid concurrent changes
2019-07-25 08:46:02 +00:00
err := h . readDB . Do ( ctx , func ( tx * db . Tx ) error {
2019-05-03 10:47:22 +00:00
var err error
2019-05-03 21:35:25 +00:00
user , err = h . readDB . GetUser ( tx , req . UserRef )
2019-05-03 10:47:22 +00:00
if err != nil {
return err
}
if user == nil {
2022-02-21 11:19:55 +00:00
return util . NewAPIError ( util . ErrBadRequest , errors . Errorf ( "user %q doesn't exist" , req . UserRef ) )
2019-05-03 10:47:22 +00:00
}
2019-05-03 21:35:25 +00:00
cgt , err = h . readDB . GetChangeGroupsUpdateTokens ( tx , cgNames )
2019-05-03 10:47:22 +00:00
if err != nil {
return err
}
if req . UserName != "" {
// check duplicate user name
2019-05-03 21:35:25 +00:00
u , err := h . readDB . GetUserByName ( tx , req . UserName )
2019-05-03 10:47:22 +00:00
if err != nil {
return err
}
if u != nil {
2022-02-21 11:19:55 +00:00
return util . NewAPIError ( util . ErrBadRequest , errors . Errorf ( "user with name %q already exists" , u . Name ) )
2019-05-03 10:47:22 +00:00
}
// changegroup is the username (and in future the email) to ensure no
// concurrent user creation/modification using the same name
cgNames = append ( cgNames , util . EncodeSha256Hex ( "username-" + req . UserName ) )
}
return nil
} )
if err != nil {
return nil , err
}
if req . UserName != "" {
user . Name = req . UserName
}
userj , err := json . Marshal ( user )
if err != nil {
2019-05-23 09:23:14 +00:00
return nil , errors . Errorf ( "failed to marshal user: %w" , err )
2019-05-03 10:47:22 +00:00
}
actions := [ ] * datamanager . Action {
{
ActionType : datamanager . ActionTypePut ,
DataType : string ( types . ConfigTypeUser ) ,
ID : user . ID ,
Data : userj ,
} ,
}
2019-05-03 21:35:25 +00:00
_ , err = h . dm . WriteWal ( ctx , actions , cgt )
2019-05-03 10:47:22 +00:00
return user , err
}
type CreateUserLARequest struct {
UserRef string
RemoteSourceName string
RemoteUserID string
RemoteUserName string
UserAccessToken string
Oauth2AccessToken string
Oauth2RefreshToken string
Oauth2AccessTokenExpiresAt time . Time
}
2019-05-03 21:35:25 +00:00
func ( h * ActionHandler ) CreateUserLA ( ctx context . Context , req * CreateUserLARequest ) ( * types . LinkedAccount , error ) {
2019-05-03 10:47:22 +00:00
if req . UserRef == "" {
2022-02-21 11:19:55 +00:00
return nil , util . NewAPIError ( util . ErrBadRequest , errors . Errorf ( "user ref required" ) )
2019-05-03 10:47:22 +00:00
}
if req . RemoteSourceName == "" {
2022-02-21 11:19:55 +00:00
return nil , util . NewAPIError ( util . ErrBadRequest , errors . Errorf ( "remote source name required" ) )
2019-05-03 10:47:22 +00:00
}
var user * types . User
var rs * types . RemoteSource
var cgt * datamanager . ChangeGroupsUpdateToken
// must do all the checks in a single transaction to avoid concurrent changes
2019-07-25 08:46:02 +00:00
err := h . readDB . Do ( ctx , func ( tx * db . Tx ) error {
2019-05-03 10:47:22 +00:00
var err error
2019-05-03 21:35:25 +00:00
user , err = h . readDB . GetUser ( tx , req . UserRef )
2019-05-03 10:47:22 +00:00
if err != nil {
return err
}
if user == nil {
2022-02-21 11:19:55 +00:00
return util . NewAPIError ( util . ErrBadRequest , errors . Errorf ( "user %q doesn't exist" , req . UserRef ) )
2019-05-03 10:47:22 +00:00
}
// changegroup is the userid
cgNames := [ ] string { util . EncodeSha256Hex ( "userid-" + user . ID ) }
2019-05-03 21:35:25 +00:00
cgt , err = h . readDB . GetChangeGroupsUpdateTokens ( tx , cgNames )
2019-05-03 10:47:22 +00:00
if err != nil {
return err
}
2019-05-03 21:35:25 +00:00
rs , err = h . readDB . GetRemoteSourceByName ( tx , req . RemoteSourceName )
2019-05-03 10:47:22 +00:00
if err != nil {
return err
}
if rs == nil {
2022-02-21 11:19:55 +00:00
return util . NewAPIError ( util . ErrBadRequest , errors . Errorf ( "remote source %q doesn't exist" , req . RemoteSourceName ) )
2019-05-03 10:47:22 +00:00
}
2019-05-03 21:35:25 +00:00
user , err := h . readDB . GetUserByLinkedAccountRemoteUserIDandSource ( tx , req . RemoteUserID , rs . ID )
2019-05-03 10:47:22 +00:00
if err != nil {
2019-05-23 09:23:14 +00:00
return errors . Errorf ( "failed to get user for remote user id %q and remote source %q: %w" , req . RemoteUserID , rs . ID , err )
2019-05-03 10:47:22 +00:00
}
if user != nil {
2022-02-21 11:19:55 +00:00
return util . NewAPIError ( util . ErrBadRequest , errors . Errorf ( "user for remote user id %q for remote source %q already exists" , req . RemoteUserID , req . RemoteSourceName ) )
2019-05-03 10:47:22 +00:00
}
return nil
} )
if err != nil {
return nil , err
}
if user . LinkedAccounts == nil {
user . LinkedAccounts = make ( map [ string ] * types . LinkedAccount )
}
la := & types . LinkedAccount {
2022-02-21 08:40:18 +00:00
ID : uuid . Must ( uuid . NewV4 ( ) ) . String ( ) ,
2019-05-03 10:47:22 +00:00
RemoteSourceID : rs . ID ,
RemoteUserID : req . RemoteUserID ,
RemoteUserName : req . RemoteUserName ,
UserAccessToken : req . UserAccessToken ,
Oauth2AccessToken : req . Oauth2AccessToken ,
Oauth2RefreshToken : req . Oauth2RefreshToken ,
Oauth2AccessTokenExpiresAt : req . Oauth2AccessTokenExpiresAt ,
}
user . LinkedAccounts [ la . ID ] = la
userj , err := json . Marshal ( user )
if err != nil {
2019-05-23 09:23:14 +00:00
return nil , errors . Errorf ( "failed to marshal user: %w" , err )
2019-05-03 10:47:22 +00:00
}
actions := [ ] * datamanager . Action {
{
ActionType : datamanager . ActionTypePut ,
DataType : string ( types . ConfigTypeUser ) ,
ID : user . ID ,
Data : userj ,
} ,
}
2019-05-03 21:35:25 +00:00
_ , err = h . dm . WriteWal ( ctx , actions , cgt )
2019-05-03 10:47:22 +00:00
return la , err
}
2019-05-03 21:35:25 +00:00
func ( h * ActionHandler ) DeleteUserLA ( ctx context . Context , userRef , laID string ) error {
2019-05-03 10:47:22 +00:00
if userRef == "" {
2022-02-21 11:19:55 +00:00
return util . NewAPIError ( util . ErrBadRequest , errors . Errorf ( "user ref required" ) )
2019-05-03 10:47:22 +00:00
}
if laID == "" {
2022-02-21 11:19:55 +00:00
return util . NewAPIError ( util . ErrBadRequest , errors . Errorf ( "user linked account id required" ) )
2019-05-03 10:47:22 +00:00
}
var user * types . User
var cgt * datamanager . ChangeGroupsUpdateToken
// must do all the checks in a single transaction to avoid concurrent changes
2019-07-25 08:46:02 +00:00
err := h . readDB . Do ( ctx , func ( tx * db . Tx ) error {
2019-05-03 10:47:22 +00:00
var err error
2019-05-03 21:35:25 +00:00
user , err = h . readDB . GetUser ( tx , userRef )
2019-05-03 10:47:22 +00:00
if err != nil {
return err
}
if user == nil {
2022-02-21 11:19:55 +00:00
return util . NewAPIError ( util . ErrBadRequest , errors . Errorf ( "user %q doesn't exist" , userRef ) )
2019-05-03 10:47:22 +00:00
}
// changegroup is the userid
cgNames := [ ] string { util . EncodeSha256Hex ( "userid-" + user . ID ) }
2019-05-03 21:35:25 +00:00
cgt , err = h . readDB . GetChangeGroupsUpdateTokens ( tx , cgNames )
2019-05-03 10:47:22 +00:00
if err != nil {
return err
}
return nil
} )
if err != nil {
return err
}
_ , ok := user . LinkedAccounts [ laID ]
if ! ok {
2022-02-21 11:19:55 +00:00
return util . NewAPIError ( util . ErrBadRequest , errors . Errorf ( "linked account id %q for user %q doesn't exist" , laID , userRef ) )
2019-05-03 10:47:22 +00:00
}
delete ( user . LinkedAccounts , laID )
userj , err := json . Marshal ( user )
if err != nil {
2019-05-23 09:23:14 +00:00
return errors . Errorf ( "failed to marshal user: %w" , err )
2019-05-03 10:47:22 +00:00
}
actions := [ ] * datamanager . Action {
{
ActionType : datamanager . ActionTypePut ,
DataType : string ( types . ConfigTypeUser ) ,
ID : user . ID ,
Data : userj ,
} ,
}
2019-05-03 21:35:25 +00:00
_ , err = h . dm . WriteWal ( ctx , actions , cgt )
2019-05-03 10:47:22 +00:00
return err
}
type UpdateUserLARequest struct {
UserRef string
LinkedAccountID string
RemoteUserID string
RemoteUserName string
UserAccessToken string
Oauth2AccessToken string
Oauth2RefreshToken string
Oauth2AccessTokenExpiresAt time . Time
}
2019-05-03 21:35:25 +00:00
func ( h * ActionHandler ) UpdateUserLA ( ctx context . Context , req * UpdateUserLARequest ) ( * types . LinkedAccount , error ) {
2019-05-03 10:47:22 +00:00
if req . UserRef == "" {
2022-02-21 11:19:55 +00:00
return nil , util . NewAPIError ( util . ErrBadRequest , errors . Errorf ( "user ref required" ) )
2019-05-03 10:47:22 +00:00
}
var user * types . User
var rs * types . RemoteSource
var cgt * datamanager . ChangeGroupsUpdateToken
// must do all the checks in a single transaction to avoid concurrent changes
2019-07-25 08:46:02 +00:00
err := h . readDB . Do ( ctx , func ( tx * db . Tx ) error {
2019-05-03 10:47:22 +00:00
var err error
2019-05-03 21:35:25 +00:00
user , err = h . readDB . GetUser ( tx , req . UserRef )
2019-05-03 10:47:22 +00:00
if err != nil {
return err
}
if user == nil {
2022-02-21 11:19:55 +00:00
return util . NewAPIError ( util . ErrBadRequest , errors . Errorf ( "user %q doesn't exist" , req . UserRef ) )
2019-05-03 10:47:22 +00:00
}
// changegroup is the userid
cgNames := [ ] string { util . EncodeSha256Hex ( "userid-" + user . ID ) }
2019-05-03 21:35:25 +00:00
cgt , err = h . readDB . GetChangeGroupsUpdateTokens ( tx , cgNames )
2019-05-03 10:47:22 +00:00
if err != nil {
return err
}
la , ok := user . LinkedAccounts [ req . LinkedAccountID ]
if ! ok {
2022-02-21 11:19:55 +00:00
return util . NewAPIError ( util . ErrBadRequest , errors . Errorf ( "linked account id %q for user %q doesn't exist" , req . LinkedAccountID , user . Name ) )
2019-05-03 10:47:22 +00:00
}
2019-05-03 21:35:25 +00:00
rs , err = h . readDB . GetRemoteSource ( tx , la . RemoteSourceID )
2019-05-03 10:47:22 +00:00
if err != nil {
return err
}
if rs == nil {
2022-02-21 11:19:55 +00:00
return util . NewAPIError ( util . ErrBadRequest , errors . Errorf ( "remote source with id %q doesn't exist" , la . RemoteSourceID ) )
2019-05-03 10:47:22 +00:00
}
return nil
} )
if err != nil {
return nil , err
}
la := user . LinkedAccounts [ req . LinkedAccountID ]
la . RemoteUserID = req . RemoteUserID
la . RemoteUserName = req . RemoteUserName
la . UserAccessToken = req . UserAccessToken
la . Oauth2AccessToken = req . Oauth2AccessToken
la . Oauth2RefreshToken = req . Oauth2RefreshToken
la . Oauth2AccessTokenExpiresAt = req . Oauth2AccessTokenExpiresAt
userj , err := json . Marshal ( user )
if err != nil {
2019-05-23 09:23:14 +00:00
return nil , errors . Errorf ( "failed to marshal user: %w" , err )
2019-05-03 10:47:22 +00:00
}
actions := [ ] * datamanager . Action {
{
ActionType : datamanager . ActionTypePut ,
DataType : string ( types . ConfigTypeUser ) ,
ID : user . ID ,
Data : userj ,
} ,
}
2019-05-03 21:35:25 +00:00
_ , err = h . dm . WriteWal ( ctx , actions , cgt )
2019-05-03 10:47:22 +00:00
return la , err
}
2019-05-03 21:35:25 +00:00
func ( h * ActionHandler ) CreateUserToken ( ctx context . Context , userRef , tokenName string ) ( string , error ) {
2019-05-03 10:47:22 +00:00
if userRef == "" {
2022-02-21 11:19:55 +00:00
return "" , util . NewAPIError ( util . ErrBadRequest , errors . Errorf ( "user ref required" ) )
2019-05-03 10:47:22 +00:00
}
if tokenName == "" {
2022-02-21 11:19:55 +00:00
return "" , util . NewAPIError ( util . ErrBadRequest , errors . Errorf ( "token name required" ) )
2019-05-03 10:47:22 +00:00
}
var user * types . User
var cgt * datamanager . ChangeGroupsUpdateToken
// must do all the checks in a single transaction to avoid concurrent changes
2019-07-25 08:46:02 +00:00
err := h . readDB . Do ( ctx , func ( tx * db . Tx ) error {
2019-05-03 10:47:22 +00:00
var err error
2019-05-03 21:35:25 +00:00
user , err = h . readDB . GetUser ( tx , userRef )
2019-05-03 10:47:22 +00:00
if err != nil {
return err
}
if user == nil {
2022-02-21 11:19:55 +00:00
return util . NewAPIError ( util . ErrBadRequest , errors . Errorf ( "user %q doesn't exist" , userRef ) )
2019-05-03 10:47:22 +00:00
}
// changegroup is the userid
cgNames := [ ] string { util . EncodeSha256Hex ( "userid-" + user . ID ) }
2019-05-03 21:35:25 +00:00
cgt , err = h . readDB . GetChangeGroupsUpdateTokens ( tx , cgNames )
2019-05-03 10:47:22 +00:00
if err != nil {
return err
}
return nil
} )
if err != nil {
return "" , err
}
if user . Tokens != nil {
if _ , ok := user . Tokens [ tokenName ] ; ok {
2022-02-21 11:19:55 +00:00
return "" , util . NewAPIError ( util . ErrBadRequest , errors . Errorf ( "token %q for user %q already exists" , tokenName , userRef ) )
2019-05-03 10:47:22 +00:00
}
}
if user . Tokens == nil {
user . Tokens = make ( map [ string ] string )
}
2022-02-21 08:40:18 +00:00
token := util . EncodeSha1Hex ( uuid . Must ( uuid . NewV4 ( ) ) . String ( ) )
2019-05-03 10:47:22 +00:00
user . Tokens [ tokenName ] = token
userj , err := json . Marshal ( user )
if err != nil {
2019-05-23 09:23:14 +00:00
return "" , errors . Errorf ( "failed to marshal user: %w" , err )
2019-05-03 10:47:22 +00:00
}
actions := [ ] * datamanager . Action {
{
ActionType : datamanager . ActionTypePut ,
DataType : string ( types . ConfigTypeUser ) ,
ID : user . ID ,
Data : userj ,
} ,
}
2019-05-03 21:35:25 +00:00
_ , err = h . dm . WriteWal ( ctx , actions , cgt )
2019-05-03 10:47:22 +00:00
return token , err
}
2019-05-03 21:35:25 +00:00
func ( h * ActionHandler ) DeleteUserToken ( ctx context . Context , userRef , tokenName string ) error {
2019-05-03 10:47:22 +00:00
if userRef == "" {
2022-02-21 11:19:55 +00:00
return util . NewAPIError ( util . ErrBadRequest , errors . Errorf ( "user ref required" ) )
2019-05-03 10:47:22 +00:00
}
if tokenName == "" {
2022-02-21 11:19:55 +00:00
return util . NewAPIError ( util . ErrBadRequest , errors . Errorf ( "token name required" ) )
2019-05-03 10:47:22 +00:00
}
var user * types . User
var cgt * datamanager . ChangeGroupsUpdateToken
// must do all the checks in a single transaction to avoid concurrent changes
2019-07-25 08:46:02 +00:00
err := h . readDB . Do ( ctx , func ( tx * db . Tx ) error {
2019-05-03 10:47:22 +00:00
var err error
2019-05-03 21:35:25 +00:00
user , err = h . readDB . GetUser ( tx , userRef )
2019-05-03 10:47:22 +00:00
if err != nil {
return err
}
if user == nil {
2022-02-21 11:19:55 +00:00
return util . NewAPIError ( util . ErrBadRequest , errors . Errorf ( "user %q doesn't exist" , userRef ) )
2019-05-03 10:47:22 +00:00
}
// changegroup is the userid
cgNames := [ ] string { util . EncodeSha256Hex ( "userid-" + user . ID ) }
2019-05-03 21:35:25 +00:00
cgt , err = h . readDB . GetChangeGroupsUpdateTokens ( tx , cgNames )
2019-05-03 10:47:22 +00:00
if err != nil {
return err
}
return nil
} )
if err != nil {
return err
}
_ , ok := user . Tokens [ tokenName ]
if ! ok {
2022-02-21 11:19:55 +00:00
return util . NewAPIError ( util . ErrBadRequest , errors . Errorf ( "token %q for user %q doesn't exist" , tokenName , userRef ) )
2019-05-03 10:47:22 +00:00
}
delete ( user . Tokens , tokenName )
userj , err := json . Marshal ( user )
if err != nil {
2019-05-23 09:23:14 +00:00
return errors . Errorf ( "failed to marshal user: %w" , err )
2019-05-03 10:47:22 +00:00
}
actions := [ ] * datamanager . Action {
{
ActionType : datamanager . ActionTypePut ,
DataType : string ( types . ConfigTypeUser ) ,
ID : user . ID ,
Data : userj ,
} ,
}
2019-05-03 21:35:25 +00:00
_ , err = h . dm . WriteWal ( ctx , actions , cgt )
2019-05-03 10:47:22 +00:00
return err
}
2019-05-03 15:40:07 +00:00
type UserOrgsResponse struct {
Organization * types . Organization
Role types . MemberRole
}
func userOrgsResponse ( userOrg * readdb . UserOrg ) * UserOrgsResponse {
return & UserOrgsResponse {
Organization : userOrg . Organization ,
Role : userOrg . Role ,
}
}
2019-05-03 21:35:25 +00:00
func ( h * ActionHandler ) GetUserOrgs ( ctx context . Context , userRef string ) ( [ ] * UserOrgsResponse , error ) {
2019-05-03 15:40:07 +00:00
var userOrgs [ ] * readdb . UserOrg
2019-07-25 08:46:02 +00:00
err := h . readDB . Do ( ctx , func ( tx * db . Tx ) error {
2019-05-03 15:40:07 +00:00
var err error
2019-05-03 21:35:25 +00:00
user , err := h . readDB . GetUser ( tx , userRef )
2019-05-03 15:40:07 +00:00
if err != nil {
return err
}
if user == nil {
2022-02-21 11:19:55 +00:00
return util . NewAPIError ( util . ErrNotExist , errors . Errorf ( "user %q doesn't exist" , userRef ) )
2019-05-03 15:40:07 +00:00
}
2019-05-03 21:35:25 +00:00
userOrgs , err = h . readDB . GetUserOrgs ( tx , user . ID )
2019-05-03 15:40:07 +00:00
return err
} )
if err != nil {
return nil , err
}
res := make ( [ ] * UserOrgsResponse , len ( userOrgs ) )
for i , userOrg := range userOrgs {
res [ i ] = userOrgsResponse ( userOrg )
}
return res , nil
}