2021-05-11 00:10:19 -05:00
package libraryelements
import (
2021-09-14 09:08:04 -05:00
"context"
2021-05-11 00:10:19 -05:00
"encoding/json"
2021-09-10 04:22:13 -05:00
"errors"
2021-05-11 00:10:19 -05:00
"fmt"
"strings"
"time"
"github.com/grafana/grafana/pkg/api/dtos"
2022-10-19 08:02:15 -05:00
"github.com/grafana/grafana/pkg/infra/db"
2023-01-29 22:14:12 -06:00
"github.com/grafana/grafana/pkg/kinds/librarypanel"
2023-10-11 18:30:50 -05:00
ac "github.com/grafana/grafana/pkg/services/accesscontrol"
2023-09-06 04:16:10 -05:00
"github.com/grafana/grafana/pkg/services/auth/identity"
2022-06-30 08:31:54 -05:00
"github.com/grafana/grafana/pkg/services/dashboards"
2023-04-06 03:16:15 -05:00
"github.com/grafana/grafana/pkg/services/featuremgmt"
2023-02-01 10:32:05 -06:00
"github.com/grafana/grafana/pkg/services/libraryelements/model"
2022-08-10 04:56:48 -05:00
"github.com/grafana/grafana/pkg/services/org"
2021-05-18 07:52:19 -05:00
"github.com/grafana/grafana/pkg/services/search"
"github.com/grafana/grafana/pkg/services/sqlstore/migrator"
2022-10-14 14:33:06 -05:00
"github.com/grafana/grafana/pkg/setting"
2021-05-11 00:10:19 -05:00
"github.com/grafana/grafana/pkg/util"
)
const (
selectLibraryElementDTOWithMeta = `
SELECT DISTINCT
le . name , le . id , le . org_id , le . folder_id , le . uid , le . kind , le . type , le . description , le . model , le . created , le . created_by , le . updated , le . updated_by , le . version
, u1 . login AS created_by_name
, u1 . email AS created_by_email
, u2 . login AS updated_by_name
, u2 . email AS updated_by_email
2023-02-01 10:32:05 -06:00
, ( SELECT COUNT ( connection_id ) FROM ` + model.LibraryElementConnectionTableName + ` WHERE element_id = le . id AND kind = 1 ) AS connected_dashboards `
2021-05-18 07:52:19 -05:00
)
2022-09-05 08:28:32 -05:00
// redundant SELECT to trick mysql's optimizer
2022-08-09 08:55:36 -05:00
const deleteInvalidConnections = `
DELETE FROM library_element_connection
WHERE connection_id IN (
2022-09-05 08:28:32 -05:00
SELECT connection_id FROM (
SELECT connection_id as id FROM library_element_connection
WHERE element_id = ? AND connection_id NOT IN ( SELECT id as connection_id from dashboard )
) as dummy
2022-08-09 08:55:36 -05:00
) `
2022-06-29 07:56:40 -05:00
2021-05-18 07:52:19 -05:00
func getFromLibraryElementDTOWithMeta ( dialect migrator . Dialect ) string {
user := dialect . Quote ( "user" )
userJoin := `
2021-05-11 00:10:19 -05:00
FROM library_element AS le
2021-05-18 07:52:19 -05:00
LEFT JOIN ` + user + ` AS u1 ON le . created_by = u1 . id
LEFT JOIN ` + user + ` AS u2 ON le . updated_by = u2 . id
2021-05-11 00:10:19 -05:00
`
2021-05-18 07:52:19 -05:00
return userJoin
}
2021-05-11 00:10:19 -05:00
2023-02-01 10:32:05 -06:00
func syncFieldsWithModel ( libraryElement * model . LibraryElement ) error {
2023-08-30 10:46:47 -05:00
var modelLibraryElement map [ string ] any
2023-02-01 10:32:05 -06:00
if err := json . Unmarshal ( libraryElement . Model , & modelLibraryElement ) ; err != nil {
2021-05-11 00:10:19 -05:00
return err
}
2023-10-23 10:16:46 -05:00
if modelLibraryElement == nil {
modelLibraryElement = make ( map [ string ] any )
}
2023-02-01 10:32:05 -06:00
if model . LibraryElementKind ( libraryElement . Kind ) == model . VariableElement {
modelLibraryElement [ "name" ] = libraryElement . Name
2021-05-11 00:10:19 -05:00
}
2023-02-01 10:32:05 -06:00
if modelLibraryElement [ "type" ] != nil {
libraryElement . Type = modelLibraryElement [ "type" ] . ( string )
2021-05-11 00:10:19 -05:00
} else {
2023-02-01 10:32:05 -06:00
modelLibraryElement [ "type" ] = libraryElement . Type
2021-05-11 00:10:19 -05:00
}
2023-02-01 10:32:05 -06:00
if modelLibraryElement [ "description" ] != nil {
libraryElement . Description = modelLibraryElement [ "description" ] . ( string )
2021-05-11 00:10:19 -05:00
} else {
2023-02-01 10:32:05 -06:00
modelLibraryElement [ "description" ] = libraryElement . Description
2021-05-11 00:10:19 -05:00
}
2023-02-01 10:32:05 -06:00
syncedModel , err := json . Marshal ( & modelLibraryElement )
2021-05-11 00:10:19 -05:00
if err != nil {
return err
}
libraryElement . Model = syncedModel
return nil
}
2023-10-11 18:30:50 -05:00
func GetLibraryElement ( dialect migrator . Dialect , session * db . Session , uid string , orgID int64 ) ( model . LibraryElementWithMeta , error ) {
2023-02-01 10:32:05 -06:00
elements := make ( [ ] model . LibraryElementWithMeta , 0 )
2021-05-11 00:10:19 -05:00
sql := selectLibraryElementDTOWithMeta +
", coalesce(dashboard.title, 'General') AS folder_name" +
", coalesce(dashboard.uid, '') AS folder_uid" +
2021-05-18 07:52:19 -05:00
getFromLibraryElementDTOWithMeta ( dialect ) +
2021-05-11 00:10:19 -05:00
" LEFT JOIN dashboard AS dashboard ON dashboard.id = le.folder_id" +
" WHERE le.uid=? AND le.org_id=?"
sess := session . SQL ( sql , uid , orgID )
err := sess . Find ( & elements )
if err != nil {
2023-02-01 10:32:05 -06:00
return model . LibraryElementWithMeta { } , err
2021-05-11 00:10:19 -05:00
}
if len ( elements ) == 0 {
2023-02-01 10:32:05 -06:00
return model . LibraryElementWithMeta { } , model . ErrLibraryElementNotFound
2021-05-11 00:10:19 -05:00
}
if len ( elements ) > 1 {
2023-02-01 10:32:05 -06:00
return model . LibraryElementWithMeta { } , fmt . Errorf ( "found %d elements, while expecting at most one" , len ( elements ) )
2021-05-11 00:10:19 -05:00
}
return elements [ 0 ] , nil
}
// createLibraryElement adds a library element.
2023-09-06 04:16:10 -05:00
func ( l * LibraryElementService ) createLibraryElement ( c context . Context , signedInUser identity . Requester , cmd model . CreateLibraryElementCommand ) ( model . LibraryElementDTO , error ) {
2021-05-11 00:10:19 -05:00
if err := l . requireSupportedElementKind ( cmd . Kind ) ; err != nil {
2023-02-01 10:32:05 -06:00
return model . LibraryElementDTO { } , err
2021-05-11 00:10:19 -05:00
}
2021-09-10 04:22:13 -05:00
createUID := cmd . UID
if len ( createUID ) == 0 {
createUID = util . GenerateShortUID ( )
} else {
if ! util . IsValidShortUID ( createUID ) {
2023-02-01 10:32:05 -06:00
return model . LibraryElementDTO { } , model . ErrLibraryElementInvalidUID
2021-09-10 04:22:13 -05:00
} else if util . IsShortUIDTooLong ( createUID ) {
2023-02-01 10:32:05 -06:00
return model . LibraryElementDTO { } , model . ErrLibraryElementUIDTooLong
2021-09-10 04:22:13 -05:00
}
}
2023-07-27 11:11:15 -05:00
updatedModel := cmd . Model
var err error
if cmd . Kind == int64 ( model . PanelElement ) {
updatedModel , err = l . addUidToLibraryPanel ( cmd . Model , createUID )
if err != nil {
return model . LibraryElementDTO { } , err
}
}
2023-09-06 04:16:10 -05:00
userID := int64 ( 0 )
namespaceID , identifier := signedInUser . GetNamespacedID ( )
switch namespaceID {
case identity . NamespaceUser , identity . NamespaceServiceAccount :
userID , err = identity . IntIdentifier ( namespaceID , identifier )
if err != nil {
l . log . Warn ( "Error while parsing userID" , "namespaceID" , namespaceID , "userID" , identifier )
}
}
2023-02-01 10:32:05 -06:00
element := model . LibraryElement {
2023-09-06 04:16:10 -05:00
OrgID : signedInUser . GetOrgID ( ) ,
2023-10-31 12:02:53 -05:00
FolderID : cmd . FolderID , // nolint:staticcheck
2021-09-10 04:22:13 -05:00
UID : createUID ,
2021-05-11 00:10:19 -05:00
Name : cmd . Name ,
2023-07-27 11:11:15 -05:00
Model : updatedModel ,
2021-05-11 00:10:19 -05:00
Version : 1 ,
Kind : cmd . Kind ,
Created : time . Now ( ) ,
Updated : time . Now ( ) ,
2023-09-06 04:16:10 -05:00
CreatedBy : userID ,
UpdatedBy : userID ,
2021-05-11 00:10:19 -05:00
}
if err := syncFieldsWithModel ( & element ) ; err != nil {
2023-02-01 10:32:05 -06:00
return model . LibraryElementDTO { } , err
2021-05-11 00:10:19 -05:00
}
2023-07-27 11:11:15 -05:00
err = l . SQLStore . WithTransactionalDbSession ( c , func ( session * db . Session ) error {
2023-11-14 14:50:27 -06:00
if l . features . IsEnabled ( c , featuremgmt . FlagLibraryPanelRBAC ) {
2023-10-11 18:30:50 -05:00
allowed , err := l . AccessControl . Evaluate ( c , signedInUser , ac . EvalPermission ( ActionLibraryPanelsCreate , dashboards . ScopeFoldersProvider . GetResourceScopeUID ( * cmd . FolderUID ) ) )
if ! allowed {
return fmt . Errorf ( "insufficient permissions for creating library panel in folder with UID %s" , * cmd . FolderUID )
}
if err != nil {
return err
}
} else {
2023-10-31 12:24:16 -05:00
// nolint:staticcheck
2023-10-11 18:30:50 -05:00
if err := l . requireEditPermissionsOnFolder ( c , signedInUser , cmd . FolderID ) ; err != nil {
return err
}
2021-05-11 00:10:19 -05:00
}
if _ , err := session . Insert ( & element ) ; err != nil {
2022-10-14 14:33:06 -05:00
if l . SQLStore . GetDialect ( ) . IsUniqueConstraintViolation ( err ) {
2023-02-01 10:32:05 -06:00
return model . ErrLibraryElementAlreadyExists
2021-05-11 00:10:19 -05:00
}
return err
}
return nil
} )
2023-02-01 10:32:05 -06:00
dto := model . LibraryElementDTO {
2021-05-11 00:10:19 -05:00
ID : element . ID ,
OrgID : element . OrgID ,
2023-10-31 12:02:53 -05:00
FolderID : element . FolderID , // nolint:staticcheck
2021-05-11 00:10:19 -05:00
UID : element . UID ,
Name : element . Name ,
Kind : element . Kind ,
Type : element . Type ,
Description : element . Description ,
Model : element . Model ,
Version : element . Version ,
2023-02-01 10:32:05 -06:00
Meta : model . LibraryElementDTOMeta {
2021-05-12 01:48:17 -05:00
ConnectedDashboards : 0 ,
Created : element . Created ,
Updated : element . Updated ,
2023-01-29 22:14:12 -06:00
CreatedBy : librarypanel . LibraryElementDTOMetaUser {
Id : element . CreatedBy ,
2023-09-06 04:16:10 -05:00
Name : signedInUser . GetLogin ( ) ,
AvatarUrl : dtos . GetGravatarUrl ( signedInUser . GetEmail ( ) ) ,
2021-05-11 00:10:19 -05:00
} ,
2023-01-29 22:14:12 -06:00
UpdatedBy : librarypanel . LibraryElementDTOMetaUser {
Id : element . UpdatedBy ,
2023-09-06 04:16:10 -05:00
Name : signedInUser . GetLogin ( ) ,
AvatarUrl : dtos . GetGravatarUrl ( signedInUser . GetEmail ( ) ) ,
2021-05-11 00:10:19 -05:00
} ,
} ,
}
return dto , err
}
// deleteLibraryElement deletes a library element.
2023-10-06 04:38:20 -05:00
func ( l * LibraryElementService ) deleteLibraryElement ( c context . Context , signedInUser identity . Requester , uid string ) ( int64 , error ) {
2021-11-05 09:06:14 -05:00
var elementID int64
2022-10-19 08:02:15 -05:00
err := l . SQLStore . WithTransactionalDbSession ( c , func ( session * db . Session ) error {
2023-10-11 18:30:50 -05:00
element , err := GetLibraryElement ( l . SQLStore . GetDialect ( ) , session , uid , signedInUser . GetOrgID ( ) )
2021-05-11 00:10:19 -05:00
if err != nil {
return err
}
2023-10-31 10:50:02 -05:00
// nolint:staticcheck
2022-06-13 08:26:17 -05:00
if err := l . requireEditPermissionsOnFolder ( c , signedInUser , element . FolderID ) ; err != nil {
2021-05-11 00:10:19 -05:00
return err
}
2022-06-29 07:56:40 -05:00
// Delete any hanging/invalid connections
if _ , err = session . Exec ( deleteInvalidConnections , element . ID ) ; err != nil {
return err
}
2021-05-11 00:10:19 -05:00
var connectionIDs [ ] struct {
ConnectionID int64 ` xorm:"connection_id" `
}
2021-05-12 01:48:17 -05:00
sql := "SELECT connection_id FROM library_element_connection WHERE element_id=?"
2021-05-11 00:10:19 -05:00
if err := session . SQL ( sql , element . ID ) . Find ( & connectionIDs ) ; err != nil {
return err
} else if len ( connectionIDs ) > 0 {
2023-02-01 10:32:05 -06:00
return model . ErrLibraryElementHasConnections
2021-05-11 00:10:19 -05:00
}
result , err := session . Exec ( "DELETE FROM library_element WHERE id=?" , element . ID )
if err != nil {
return err
}
if rowsAffected , err := result . RowsAffected ( ) ; err != nil {
return err
} else if rowsAffected != 1 {
2023-02-01 10:32:05 -06:00
return model . ErrLibraryElementNotFound
2021-05-11 00:10:19 -05:00
}
2021-11-05 09:06:14 -05:00
elementID = element . ID
2021-05-11 00:10:19 -05:00
return nil
} )
2021-11-05 09:06:14 -05:00
return elementID , err
2021-05-11 00:10:19 -05:00
}
2021-09-20 03:58:24 -05:00
// getLibraryElements gets a Library Element where param == value
2023-09-06 04:16:10 -05:00
func ( l * LibraryElementService ) getLibraryElements ( c context . Context , store db . DB , cfg * setting . Cfg , signedInUser identity . Requester , params [ ] Pair , features featuremgmt . FeatureToggles , cmd model . GetLibraryElementCommand ) ( [ ] model . LibraryElementDTO , error ) {
2023-02-01 10:32:05 -06:00
libraryElements := make ( [ ] model . LibraryElementWithMeta , 0 )
2023-04-06 03:16:15 -05:00
recursiveQueriesAreSupported , err := store . RecursiveQueriesAreSupported ( )
if err != nil {
return nil , err
}
err = store . WithDbSession ( c , func ( session * db . Session ) error {
builder := db . NewSqlBuilder ( cfg , features , store . GetDialect ( ) , recursiveQueriesAreSupported )
2021-05-11 00:10:19 -05:00
builder . Write ( selectLibraryElementDTOWithMeta )
2023-07-25 06:05:53 -05:00
builder . Write ( ", ? as folder_name " , cmd . FolderName )
2021-05-11 00:10:19 -05:00
builder . Write ( ", '' as folder_uid " )
2022-10-14 14:33:06 -05:00
builder . Write ( getFromLibraryElementDTOWithMeta ( store . GetDialect ( ) ) )
2023-10-31 10:46:48 -05:00
// nolint:staticcheck
2023-07-25 06:05:53 -05:00
writeParamSelectorSQL ( & builder , append ( params , Pair { "folder_id" , cmd . FolderID } ) ... )
2021-05-11 00:10:19 -05:00
builder . Write ( " UNION " )
builder . Write ( selectLibraryElementDTOWithMeta )
builder . Write ( ", dashboard.title as folder_name " )
builder . Write ( ", dashboard.uid as folder_uid " )
2022-10-14 14:33:06 -05:00
builder . Write ( getFromLibraryElementDTOWithMeta ( store . GetDialect ( ) ) )
2021-05-11 00:10:19 -05:00
builder . Write ( " INNER JOIN dashboard AS dashboard on le.folder_id = dashboard.id AND le.folder_id <> 0" )
2021-05-14 09:03:37 -05:00
writeParamSelectorSQL ( & builder , params ... )
2023-06-21 08:48:09 -05:00
builder . WriteDashboardPermissionFilter ( signedInUser , dashboards . PERMISSION_VIEW , "" )
2021-05-11 00:10:19 -05:00
builder . Write ( ` OR dashboard.id=0 ` )
if err := session . SQL ( builder . GetSQLString ( ) , builder . GetParams ( ) ... ) . Find ( & libraryElements ) ; err != nil {
return err
}
if len ( libraryElements ) == 0 {
2023-02-01 10:32:05 -06:00
return model . ErrLibraryElementNotFound
2021-05-11 00:10:19 -05:00
}
return nil
} )
if err != nil {
2023-02-01 10:32:05 -06:00
return [ ] model . LibraryElementDTO { } , err
2021-05-11 00:10:19 -05:00
}
2023-02-01 10:32:05 -06:00
leDtos := make ( [ ] model . LibraryElementDTO , len ( libraryElements ) )
2021-05-14 09:03:37 -05:00
for i , libraryElement := range libraryElements {
2023-07-27 11:11:15 -05:00
var updatedModel json . RawMessage
if libraryElement . Kind == int64 ( model . PanelElement ) {
updatedModel , err = l . addUidToLibraryPanel ( libraryElement . Model , libraryElement . UID )
if err != nil {
return [ ] model . LibraryElementDTO { } , err
}
}
2023-02-01 10:32:05 -06:00
leDtos [ i ] = model . LibraryElementDTO {
2021-05-14 09:03:37 -05:00
ID : libraryElement . ID ,
OrgID : libraryElement . OrgID ,
2023-10-31 10:50:02 -05:00
FolderID : libraryElement . FolderID , // nolint:staticcheck
2022-05-05 03:04:54 -05:00
FolderUID : libraryElement . FolderUID ,
2021-05-14 09:03:37 -05:00
UID : libraryElement . UID ,
Name : libraryElement . Name ,
Kind : libraryElement . Kind ,
Type : libraryElement . Type ,
Description : libraryElement . Description ,
2023-07-27 11:11:15 -05:00
Model : updatedModel ,
2021-05-14 09:03:37 -05:00
Version : libraryElement . Version ,
2023-02-01 10:32:05 -06:00
Meta : model . LibraryElementDTOMeta {
2021-05-14 09:03:37 -05:00
FolderName : libraryElement . FolderName ,
FolderUID : libraryElement . FolderUID ,
ConnectedDashboards : libraryElement . ConnectedDashboards ,
Created : libraryElement . Created ,
Updated : libraryElement . Updated ,
2023-01-29 22:14:12 -06:00
CreatedBy : librarypanel . LibraryElementDTOMetaUser {
Id : libraryElement . CreatedBy ,
2021-05-14 09:03:37 -05:00
Name : libraryElement . CreatedByName ,
2023-01-29 22:14:12 -06:00
AvatarUrl : dtos . GetGravatarUrl ( libraryElement . CreatedByEmail ) ,
2021-05-14 09:03:37 -05:00
} ,
2023-01-29 22:14:12 -06:00
UpdatedBy : librarypanel . LibraryElementDTOMetaUser {
Id : libraryElement . UpdatedBy ,
2021-05-14 09:03:37 -05:00
Name : libraryElement . UpdatedByName ,
2023-01-29 22:14:12 -06:00
AvatarUrl : dtos . GetGravatarUrl ( libraryElement . UpdatedByEmail ) ,
2021-05-14 09:03:37 -05:00
} ,
2021-05-11 00:10:19 -05:00
} ,
2021-05-14 09:03:37 -05:00
}
2021-05-11 00:10:19 -05:00
}
2021-05-14 09:03:37 -05:00
return leDtos , nil
}
// getLibraryElementByUid gets a Library Element by uid.
2023-09-06 04:16:10 -05:00
func ( l * LibraryElementService ) getLibraryElementByUid ( c context . Context , signedInUser identity . Requester , cmd model . GetLibraryElementCommand ) ( model . LibraryElementDTO , error ) {
libraryElements , err := l . getLibraryElements ( c , l . SQLStore , l . Cfg , signedInUser , [ ] Pair { { key : "org_id" , value : signedInUser . GetOrgID ( ) } , { key : "uid" , value : cmd . UID } } , l . features , cmd )
2021-05-14 09:03:37 -05:00
if err != nil {
2023-02-01 10:32:05 -06:00
return model . LibraryElementDTO { } , err
2021-05-14 09:03:37 -05:00
}
if len ( libraryElements ) > 1 {
2023-02-01 10:32:05 -06:00
return model . LibraryElementDTO { } , fmt . Errorf ( "found %d elements, while expecting at most one" , len ( libraryElements ) )
2021-05-14 09:03:37 -05:00
}
return libraryElements [ 0 ] , nil
}
// getLibraryElementByName gets a Library Element by name.
2023-09-06 04:16:10 -05:00
func ( l * LibraryElementService ) getLibraryElementsByName ( c context . Context , signedInUser identity . Requester , name string ) ( [ ] model . LibraryElementDTO , error ) {
return l . getLibraryElements ( c , l . SQLStore , l . Cfg , signedInUser , [ ] Pair { { "org_id" , signedInUser . GetOrgID ( ) } , { "name" , name } } , l . features ,
2023-07-25 06:05:53 -05:00
model . GetLibraryElementCommand {
FolderName : dashboards . RootFolderName ,
} )
2021-05-11 00:10:19 -05:00
}
// getAllLibraryElements gets all Library Elements.
2023-09-06 04:16:10 -05:00
func ( l * LibraryElementService ) getAllLibraryElements ( c context . Context , signedInUser identity . Requester , query model . SearchLibraryElementsQuery ) ( model . LibraryElementSearchResult , error ) {
2023-02-01 10:32:05 -06:00
elements := make ( [ ] model . LibraryElementWithMeta , 0 )
result := model . LibraryElementSearchResult { }
2023-04-06 03:16:15 -05:00
recursiveQueriesAreSupported , err := l . SQLStore . RecursiveQueriesAreSupported ( )
if err != nil {
return result , err
}
2023-02-01 10:32:05 -06:00
if query . PerPage <= 0 {
query . PerPage = 100
2021-05-11 00:10:19 -05:00
}
2023-02-01 10:32:05 -06:00
if query . Page <= 0 {
query . Page = 1
2021-05-11 00:10:19 -05:00
}
var typeFilter [ ] string
2023-02-01 10:32:05 -06:00
if len ( strings . TrimSpace ( query . TypeFilter ) ) > 0 {
typeFilter = strings . Split ( query . TypeFilter , "," )
2021-05-11 00:10:19 -05:00
}
folderFilter := parseFolderFilter ( query )
if folderFilter . parseError != nil {
2023-02-01 10:32:05 -06:00
return model . LibraryElementSearchResult { } , folderFilter . parseError
2021-05-11 00:10:19 -05:00
}
2023-04-06 03:16:15 -05:00
err = l . SQLStore . WithDbSession ( c , func ( session * db . Session ) error {
builder := db . NewSqlBuilder ( l . Cfg , l . features , l . SQLStore . GetDialect ( ) , recursiveQueriesAreSupported )
2021-05-11 00:10:19 -05:00
if folderFilter . includeGeneralFolder {
builder . Write ( selectLibraryElementDTOWithMeta )
builder . Write ( ", 'General' as folder_name " )
builder . Write ( ", '' as folder_uid " )
2022-10-14 14:33:06 -05:00
builder . Write ( getFromLibraryElementDTOWithMeta ( l . SQLStore . GetDialect ( ) ) )
2023-09-06 04:16:10 -05:00
builder . Write ( ` WHERE le.org_id=? AND le.folder_id=0 ` , signedInUser . GetOrgID ( ) )
2021-05-11 00:10:19 -05:00
writeKindSQL ( query , & builder )
writeSearchStringSQL ( query , l . SQLStore , & builder )
writeExcludeSQL ( query , & builder )
writeTypeFilterSQL ( typeFilter , & builder )
builder . Write ( " UNION " )
}
builder . Write ( selectLibraryElementDTOWithMeta )
builder . Write ( ", dashboard.title as folder_name " )
builder . Write ( ", dashboard.uid as folder_uid " )
2022-10-14 14:33:06 -05:00
builder . Write ( getFromLibraryElementDTOWithMeta ( l . SQLStore . GetDialect ( ) ) )
2021-05-11 00:10:19 -05:00
builder . Write ( " INNER JOIN dashboard AS dashboard on le.folder_id = dashboard.id AND le.folder_id<>0" )
2023-09-06 04:16:10 -05:00
builder . Write ( ` WHERE le.org_id=? ` , signedInUser . GetOrgID ( ) )
2021-05-11 00:10:19 -05:00
writeKindSQL ( query , & builder )
writeSearchStringSQL ( query , l . SQLStore , & builder )
writeExcludeSQL ( query , & builder )
writeTypeFilterSQL ( typeFilter , & builder )
if err := folderFilter . writeFolderFilterSQL ( false , & builder ) ; err != nil {
return err
}
2023-09-06 04:16:10 -05:00
if ! signedInUser . HasRole ( org . RoleAdmin ) {
2023-06-21 08:48:09 -05:00
builder . WriteDashboardPermissionFilter ( signedInUser , dashboards . PERMISSION_VIEW , "" )
2021-05-11 00:10:19 -05:00
}
2023-02-01 10:32:05 -06:00
if query . SortDirection == search . SortAlphaDesc . Name {
2021-05-11 00:10:19 -05:00
builder . Write ( " ORDER BY 1 DESC" )
} else {
builder . Write ( " ORDER BY 1 ASC" )
}
writePerPageSQL ( query , l . SQLStore , & builder )
if err := session . SQL ( builder . GetSQLString ( ) , builder . GetParams ( ) ... ) . Find ( & elements ) ; err != nil {
return err
}
2023-02-01 10:32:05 -06:00
retDTOs := make ( [ ] model . LibraryElementDTO , 0 )
2021-05-11 00:10:19 -05:00
for _ , element := range elements {
2023-02-01 10:32:05 -06:00
retDTOs = append ( retDTOs , model . LibraryElementDTO {
2021-05-11 00:10:19 -05:00
ID : element . ID ,
OrgID : element . OrgID ,
2023-10-31 10:50:02 -05:00
FolderID : element . FolderID , // nolint:staticcheck
2022-05-05 03:04:54 -05:00
FolderUID : element . FolderUID ,
2021-05-11 00:10:19 -05:00
UID : element . UID ,
Name : element . Name ,
Kind : element . Kind ,
Type : element . Type ,
Description : element . Description ,
Model : element . Model ,
Version : element . Version ,
2023-02-01 10:32:05 -06:00
Meta : model . LibraryElementDTOMeta {
2021-05-12 01:48:17 -05:00
FolderName : element . FolderName ,
FolderUID : element . FolderUID ,
ConnectedDashboards : element . ConnectedDashboards ,
Created : element . Created ,
Updated : element . Updated ,
2023-01-29 22:14:12 -06:00
CreatedBy : librarypanel . LibraryElementDTOMetaUser {
Id : element . CreatedBy ,
2021-05-11 00:10:19 -05:00
Name : element . CreatedByName ,
2023-01-29 22:14:12 -06:00
AvatarUrl : dtos . GetGravatarUrl ( element . CreatedByEmail ) ,
2021-05-11 00:10:19 -05:00
} ,
2023-01-29 22:14:12 -06:00
UpdatedBy : librarypanel . LibraryElementDTOMetaUser {
Id : element . UpdatedBy ,
2021-05-11 00:10:19 -05:00
Name : element . UpdatedByName ,
2023-01-29 22:14:12 -06:00
AvatarUrl : dtos . GetGravatarUrl ( element . UpdatedByEmail ) ,
2021-05-11 00:10:19 -05:00
} ,
} ,
} )
}
2023-02-01 10:32:05 -06:00
var libraryElements [ ] model . LibraryElement
2022-10-19 08:02:15 -05:00
countBuilder := db . SQLBuilder { }
2023-04-11 08:16:20 -05:00
if folderFilter . includeGeneralFolder {
countBuilder . Write ( selectLibraryElementDTOWithMeta )
countBuilder . Write ( getFromLibraryElementDTOWithMeta ( l . SQLStore . GetDialect ( ) ) )
2023-09-06 04:16:10 -05:00
countBuilder . Write ( ` WHERE le.org_id=? AND le.folder_id=0 ` , signedInUser . GetOrgID ( ) )
2023-04-11 08:16:20 -05:00
writeKindSQL ( query , & countBuilder )
writeSearchStringSQL ( query , l . SQLStore , & countBuilder )
writeExcludeSQL ( query , & countBuilder )
writeTypeFilterSQL ( typeFilter , & countBuilder )
countBuilder . Write ( " UNION " )
}
countBuilder . Write ( selectLibraryElementDTOWithMeta )
countBuilder . Write ( getFromLibraryElementDTOWithMeta ( l . SQLStore . GetDialect ( ) ) )
countBuilder . Write ( " INNER JOIN dashboard AS dashboard on le.folder_id = dashboard.id and le.folder_id<>0" )
2023-09-06 04:16:10 -05:00
countBuilder . Write ( ` WHERE le.org_id=? ` , signedInUser . GetOrgID ( ) )
2021-05-11 00:10:19 -05:00
writeKindSQL ( query , & countBuilder )
writeSearchStringSQL ( query , l . SQLStore , & countBuilder )
writeExcludeSQL ( query , & countBuilder )
writeTypeFilterSQL ( typeFilter , & countBuilder )
if err := folderFilter . writeFolderFilterSQL ( true , & countBuilder ) ; err != nil {
return err
}
if err := session . SQL ( countBuilder . GetSQLString ( ) , countBuilder . GetParams ( ) ... ) . Find ( & libraryElements ) ; err != nil {
return err
}
2023-02-01 10:32:05 -06:00
result = model . LibraryElementSearchResult {
2021-05-11 00:10:19 -05:00
TotalCount : int64 ( len ( libraryElements ) ) ,
Elements : retDTOs ,
2023-02-01 10:32:05 -06:00
Page : query . Page ,
PerPage : query . PerPage ,
2021-05-11 00:10:19 -05:00
}
return nil
} )
return result , err
}
2023-10-06 04:38:20 -05:00
func ( l * LibraryElementService ) handleFolderIDPatches ( ctx context . Context , elementToPatch * model . LibraryElement ,
fromFolderID int64 , toFolderID int64 , user identity . Requester ) error {
2021-05-11 00:10:19 -05:00
// FolderID was not provided in the PATCH request
if toFolderID == - 1 {
toFolderID = fromFolderID
}
// FolderID was provided in the PATCH request
if toFolderID != - 1 && toFolderID != fromFolderID {
2022-06-13 08:26:17 -05:00
if err := l . requireEditPermissionsOnFolder ( ctx , user , toFolderID ) ; err != nil {
2021-05-11 00:10:19 -05:00
return err
}
}
// Always check permissions for the folder where library element resides
2022-06-13 08:26:17 -05:00
if err := l . requireEditPermissionsOnFolder ( ctx , user , fromFolderID ) ; err != nil {
2021-05-11 00:10:19 -05:00
return err
}
2023-10-31 12:02:53 -05:00
// nolint:staticcheck
2021-05-11 00:10:19 -05:00
elementToPatch . FolderID = toFolderID
return nil
}
// patchLibraryElement updates a Library Element.
2023-10-06 04:38:20 -05:00
func ( l * LibraryElementService ) patchLibraryElement ( c context . Context , signedInUser identity . Requester , cmd model . PatchLibraryElementCommand , uid string ) ( model . LibraryElementDTO , error ) {
2023-02-01 10:32:05 -06:00
var dto model . LibraryElementDTO
2021-05-11 00:10:19 -05:00
if err := l . requireSupportedElementKind ( cmd . Kind ) ; err != nil {
2023-02-01 10:32:05 -06:00
return model . LibraryElementDTO { } , err
2021-05-11 00:10:19 -05:00
}
2022-10-19 08:02:15 -05:00
err := l . SQLStore . WithTransactionalDbSession ( c , func ( session * db . Session ) error {
2023-10-11 18:30:50 -05:00
elementInDB , err := GetLibraryElement ( l . SQLStore . GetDialect ( ) , session , uid , signedInUser . GetOrgID ( ) )
2021-05-11 00:10:19 -05:00
if err != nil {
return err
}
if elementInDB . Version != cmd . Version {
2023-02-01 10:32:05 -06:00
return model . ErrLibraryElementVersionMismatch
2021-05-11 00:10:19 -05:00
}
2021-09-10 04:22:13 -05:00
updateUID := cmd . UID
if len ( updateUID ) == 0 {
updateUID = uid
} else if updateUID != uid {
if ! util . IsValidShortUID ( updateUID ) {
2023-02-01 10:32:05 -06:00
return model . ErrLibraryElementInvalidUID
2021-09-10 04:22:13 -05:00
} else if util . IsShortUIDTooLong ( updateUID ) {
2023-02-01 10:32:05 -06:00
return model . ErrLibraryElementUIDTooLong
2021-09-10 04:22:13 -05:00
}
2023-10-11 18:30:50 -05:00
_ , err := GetLibraryElement ( l . SQLStore . GetDialect ( ) , session , updateUID , signedInUser . GetOrgID ( ) )
2023-02-01 10:32:05 -06:00
if ! errors . Is ( err , model . ErrLibraryElementNotFound ) {
return model . ErrLibraryElementAlreadyExists
2021-09-10 04:22:13 -05:00
}
}
2021-05-11 00:10:19 -05:00
2023-10-06 04:38:20 -05:00
var userID int64
namespaceID , identifier := signedInUser . GetNamespacedID ( )
switch namespaceID {
case identity . NamespaceUser , identity . NamespaceServiceAccount :
var errID error
userID , errID = identity . IntIdentifier ( namespaceID , identifier )
if errID != nil {
l . log . Warn ( "Error while parsing userID" , "namespaceID" , namespaceID , "userID" , identifier , "err" , errID )
}
}
2023-02-01 10:32:05 -06:00
var libraryElement = model . LibraryElement {
2021-05-11 00:10:19 -05:00
ID : elementInDB . ID ,
2023-10-06 04:38:20 -05:00
OrgID : signedInUser . GetOrgID ( ) ,
2023-10-31 12:02:53 -05:00
FolderID : cmd . FolderID , // nolint:staticcheck
2021-09-10 04:22:13 -05:00
UID : updateUID ,
2021-05-11 00:10:19 -05:00
Name : cmd . Name ,
Kind : elementInDB . Kind ,
Type : elementInDB . Type ,
Description : elementInDB . Description ,
Model : cmd . Model ,
Version : elementInDB . Version + 1 ,
Created : elementInDB . Created ,
CreatedBy : elementInDB . CreatedBy ,
Updated : time . Now ( ) ,
2023-10-06 04:38:20 -05:00
UpdatedBy : userID ,
2021-05-11 00:10:19 -05:00
}
if cmd . Name == "" {
libraryElement . Name = elementInDB . Name
}
if cmd . Model == nil {
libraryElement . Model = elementInDB . Model
}
2023-10-31 10:50:02 -05:00
// nolint:staticcheck
2021-09-27 02:04:36 -05:00
if err := l . handleFolderIDPatches ( c , & libraryElement , elementInDB . FolderID , cmd . FolderID , signedInUser ) ; err != nil {
2021-05-11 00:10:19 -05:00
return err
}
if err := syncFieldsWithModel ( & libraryElement ) ; err != nil {
return err
}
if rowsAffected , err := session . ID ( elementInDB . ID ) . Update ( & libraryElement ) ; err != nil {
2022-10-14 14:33:06 -05:00
if l . SQLStore . GetDialect ( ) . IsUniqueConstraintViolation ( err ) {
2023-02-01 10:32:05 -06:00
return model . ErrLibraryElementAlreadyExists
2021-05-11 00:10:19 -05:00
}
return err
} else if rowsAffected != 1 {
2023-02-01 10:32:05 -06:00
return model . ErrLibraryElementNotFound
2021-05-11 00:10:19 -05:00
}
2023-02-01 10:32:05 -06:00
dto = model . LibraryElementDTO {
2021-05-11 00:10:19 -05:00
ID : libraryElement . ID ,
OrgID : libraryElement . OrgID ,
2023-10-31 12:02:53 -05:00
FolderID : libraryElement . FolderID , // nolint:staticcheck
2021-05-11 00:10:19 -05:00
UID : libraryElement . UID ,
Name : libraryElement . Name ,
Kind : libraryElement . Kind ,
Type : libraryElement . Type ,
Description : libraryElement . Description ,
Model : libraryElement . Model ,
Version : libraryElement . Version ,
2023-02-01 10:32:05 -06:00
Meta : model . LibraryElementDTOMeta {
2021-05-12 01:48:17 -05:00
ConnectedDashboards : elementInDB . ConnectedDashboards ,
Created : libraryElement . Created ,
Updated : libraryElement . Updated ,
2023-01-29 22:14:12 -06:00
CreatedBy : librarypanel . LibraryElementDTOMetaUser {
Id : elementInDB . CreatedBy ,
2021-05-11 00:10:19 -05:00
Name : elementInDB . CreatedByName ,
2023-01-29 22:14:12 -06:00
AvatarUrl : dtos . GetGravatarUrl ( elementInDB . CreatedByEmail ) ,
2021-05-11 00:10:19 -05:00
} ,
2023-01-29 22:14:12 -06:00
UpdatedBy : librarypanel . LibraryElementDTOMetaUser {
Id : libraryElement . UpdatedBy ,
2023-10-06 04:38:20 -05:00
Name : signedInUser . GetLogin ( ) ,
AvatarUrl : dtos . GetGravatarUrl ( signedInUser . GetEmail ( ) ) ,
2021-05-11 00:10:19 -05:00
} ,
} ,
}
return nil
} )
return dto , err
}
// getConnections gets all connections for a Library Element.
2023-10-06 04:38:20 -05:00
func ( l * LibraryElementService ) getConnections ( c context . Context , signedInUser identity . Requester , uid string ) ( [ ] model . LibraryElementConnectionDTO , error ) {
2023-02-01 10:32:05 -06:00
connections := make ( [ ] model . LibraryElementConnectionDTO , 0 )
2023-04-06 03:16:15 -05:00
recursiveQueriesAreSupported , err := l . SQLStore . RecursiveQueriesAreSupported ( )
if err != nil {
return nil , err
}
err = l . SQLStore . WithDbSession ( c , func ( session * db . Session ) error {
2023-10-11 18:30:50 -05:00
element , err := GetLibraryElement ( l . SQLStore . GetDialect ( ) , session , uid , signedInUser . GetOrgID ( ) )
2021-05-11 00:10:19 -05:00
if err != nil {
return err
}
2023-02-01 10:32:05 -06:00
var libraryElementConnections [ ] model . LibraryElementConnectionWithMeta
2023-04-06 03:16:15 -05:00
builder := db . NewSqlBuilder ( l . Cfg , l . features , l . SQLStore . GetDialect ( ) , recursiveQueriesAreSupported )
2022-07-25 17:55:28 -05:00
builder . Write ( "SELECT lec.*, u1.login AS created_by_name, u1.email AS created_by_email, dashboard.uid AS connection_uid" )
2023-02-01 10:32:05 -06:00
builder . Write ( " FROM " + model . LibraryElementConnectionTableName + " AS lec" )
2022-10-14 14:33:06 -05:00
builder . Write ( " LEFT JOIN " + l . SQLStore . GetDialect ( ) . Quote ( "user" ) + " AS u1 ON lec.created_by = u1.id" )
2021-05-11 00:10:19 -05:00
builder . Write ( " INNER JOIN dashboard AS dashboard on lec.connection_id = dashboard.id" )
2021-05-12 01:48:17 -05:00
builder . Write ( ` WHERE lec.element_id=? ` , element . ID )
2023-10-06 04:38:20 -05:00
if signedInUser . GetOrgRole ( ) != org . RoleAdmin {
2023-06-21 08:48:09 -05:00
builder . WriteDashboardPermissionFilter ( signedInUser , dashboards . PERMISSION_VIEW , "" )
2021-05-11 00:10:19 -05:00
}
if err := session . SQL ( builder . GetSQLString ( ) , builder . GetParams ( ) ... ) . Find ( & libraryElementConnections ) ; err != nil {
return err
}
for _ , connection := range libraryElementConnections {
2023-02-01 10:32:05 -06:00
connections = append ( connections , model . LibraryElementConnectionDTO {
2022-07-25 17:55:28 -05:00
ID : connection . ID ,
Kind : connection . Kind ,
ElementID : connection . ElementID ,
ConnectionID : connection . ConnectionID ,
ConnectionUID : connection . ConnectionUID ,
Created : connection . Created ,
2023-01-29 22:14:12 -06:00
CreatedBy : librarypanel . LibraryElementDTOMetaUser {
Id : connection . CreatedBy ,
2021-05-11 00:10:19 -05:00
Name : connection . CreatedByName ,
2023-01-29 22:14:12 -06:00
AvatarUrl : dtos . GetGravatarUrl ( connection . CreatedByEmail ) ,
2021-05-11 00:10:19 -05:00
} ,
} )
}
return nil
} )
return connections , err
}
2022-08-09 08:55:36 -05:00
// getElementsForDashboardID gets all elements for a specific dashboard
2023-02-01 10:32:05 -06:00
func ( l * LibraryElementService ) getElementsForDashboardID ( c context . Context , dashboardID int64 ) ( map [ string ] model . LibraryElementDTO , error ) {
libraryElementMap := make ( map [ string ] model . LibraryElementDTO )
2022-10-19 08:02:15 -05:00
err := l . SQLStore . WithDbSession ( c , func ( session * db . Session ) error {
2023-02-01 10:32:05 -06:00
var libraryElements [ ] model . LibraryElementWithMeta
2021-05-11 00:10:19 -05:00
sql := selectLibraryElementDTOWithMeta +
", coalesce(dashboard.title, 'General') AS folder_name" +
", coalesce(dashboard.uid, '') AS folder_uid" +
2022-10-14 14:33:06 -05:00
getFromLibraryElementDTOWithMeta ( l . SQLStore . GetDialect ( ) ) +
2021-05-11 00:10:19 -05:00
" LEFT JOIN dashboard AS dashboard ON dashboard.id = le.folder_id" +
2023-02-01 10:32:05 -06:00
" INNER JOIN " + model . LibraryElementConnectionTableName + " AS lce ON lce.element_id = le.id AND lce.kind=1 AND lce.connection_id=?"
2021-05-11 00:10:19 -05:00
sess := session . SQL ( sql , dashboardID )
err := sess . Find ( & libraryElements )
if err != nil {
return err
}
for _ , element := range libraryElements {
2023-02-01 10:32:05 -06:00
libraryElementMap [ element . UID ] = model . LibraryElementDTO {
2021-05-11 00:10:19 -05:00
ID : element . ID ,
OrgID : element . OrgID ,
2023-10-31 10:50:02 -05:00
FolderID : element . FolderID , // nolint:staticcheck
2021-05-11 00:10:19 -05:00
UID : element . UID ,
Name : element . Name ,
Kind : element . Kind ,
Type : element . Type ,
Description : element . Description ,
Model : element . Model ,
Version : element . Version ,
2023-02-01 10:32:05 -06:00
Meta : model . LibraryElementDTOMeta {
2021-05-12 01:48:17 -05:00
FolderName : element . FolderName ,
FolderUID : element . FolderUID ,
ConnectedDashboards : element . ConnectedDashboards ,
Created : element . Created ,
Updated : element . Updated ,
2023-01-29 22:14:12 -06:00
CreatedBy : librarypanel . LibraryElementDTOMetaUser {
Id : element . CreatedBy ,
2021-05-11 00:10:19 -05:00
Name : element . CreatedByName ,
2023-01-29 22:14:12 -06:00
AvatarUrl : dtos . GetGravatarUrl ( element . CreatedByEmail ) ,
2021-05-11 00:10:19 -05:00
} ,
2023-01-29 22:14:12 -06:00
UpdatedBy : librarypanel . LibraryElementDTOMetaUser {
Id : element . UpdatedBy ,
2021-05-11 00:10:19 -05:00
Name : element . UpdatedByName ,
2023-01-29 22:14:12 -06:00
AvatarUrl : dtos . GetGravatarUrl ( element . UpdatedByEmail ) ,
2021-05-11 00:10:19 -05:00
} ,
} ,
}
}
return nil
} )
return libraryElementMap , err
}
// connectElementsToDashboardID adds connections for all elements Library Elements in a Dashboard.
2023-09-06 04:16:10 -05:00
func ( l * LibraryElementService ) connectElementsToDashboardID ( c context . Context , signedInUser identity . Requester , elementUIDs [ ] string , dashboardID int64 ) error {
2022-10-19 08:02:15 -05:00
err := l . SQLStore . WithTransactionalDbSession ( c , func ( session * db . Session ) error {
2023-02-01 10:32:05 -06:00
_ , err := session . Exec ( "DELETE FROM " + model . LibraryElementConnectionTableName + " WHERE kind=1 AND connection_id=?" , dashboardID )
2021-05-11 00:10:19 -05:00
if err != nil {
return err
}
for _ , elementUID := range elementUIDs {
2023-10-11 18:30:50 -05:00
element , err := GetLibraryElement ( l . SQLStore . GetDialect ( ) , session , elementUID , signedInUser . GetOrgID ( ) )
2021-05-11 00:10:19 -05:00
if err != nil {
return err
}
2023-10-31 10:50:02 -05:00
// nolint:staticcheck
2022-06-13 08:26:17 -05:00
if err := l . requireViewPermissionsOnFolder ( c , signedInUser , element . FolderID ) ; err != nil {
2021-05-11 00:10:19 -05:00
return err
}
2023-09-06 04:16:10 -05:00
namespaceID , identifier := signedInUser . GetNamespacedID ( )
userID := int64 ( 0 )
switch namespaceID {
case identity . NamespaceUser , identity . NamespaceServiceAccount :
userID , err = identity . IntIdentifier ( namespaceID , identifier )
if err != nil {
l . log . Warn ( "Failed to parse user ID from namespace identifier" , "namespace" , namespaceID , "identifier" , identifier , "error" , err )
}
}
2023-02-01 10:32:05 -06:00
connection := model . LibraryElementConnection {
2021-05-12 01:48:17 -05:00
ElementID : element . ID ,
Kind : 1 ,
ConnectionID : dashboardID ,
Created : time . Now ( ) ,
2023-09-06 04:16:10 -05:00
CreatedBy : userID ,
2021-05-11 00:10:19 -05:00
}
if _ , err := session . Insert ( & connection ) ; err != nil {
2022-10-14 14:33:06 -05:00
if l . SQLStore . GetDialect ( ) . IsUniqueConstraintViolation ( err ) {
2021-05-11 00:10:19 -05:00
return nil
}
return err
}
}
return nil
} )
return err
}
// disconnectElementsFromDashboardID deletes connections for all Library Elements in a Dashboard.
2021-09-27 02:04:36 -05:00
func ( l * LibraryElementService ) disconnectElementsFromDashboardID ( c context . Context , dashboardID int64 ) error {
2022-10-19 08:02:15 -05:00
return l . SQLStore . WithTransactionalDbSession ( c , func ( session * db . Session ) error {
2023-02-01 10:32:05 -06:00
_ , err := session . Exec ( "DELETE FROM " + model . LibraryElementConnectionTableName + " WHERE kind=1 AND connection_id=?" , dashboardID )
2021-05-11 00:10:19 -05:00
if err != nil {
return err
}
return nil
} )
}
// deleteLibraryElementsInFolderUID deletes all Library Elements in a folder.
2023-09-06 04:16:10 -05:00
func ( l * LibraryElementService ) deleteLibraryElementsInFolderUID ( c context . Context , signedInUser identity . Requester , folderUID string ) error {
2022-10-19 08:02:15 -05:00
return l . SQLStore . WithTransactionalDbSession ( c , func ( session * db . Session ) error {
2021-05-11 00:10:19 -05:00
var folderUIDs [ ] struct {
ID int64 ` xorm:"id" `
}
2023-09-06 04:16:10 -05:00
err := session . SQL ( "SELECT id from dashboard WHERE uid=? AND org_id=? AND is_folder=?" , folderUID , signedInUser . GetOrgID ( ) , l . SQLStore . GetDialect ( ) . BooleanStr ( true ) ) . Find ( & folderUIDs )
2021-05-11 00:10:19 -05:00
if err != nil {
return err
}
2021-11-30 07:07:04 -06:00
if len ( folderUIDs ) == 0 {
2022-06-30 08:31:54 -05:00
return dashboards . ErrFolderNotFound
2021-11-30 07:07:04 -06:00
}
2021-05-11 00:10:19 -05:00
if len ( folderUIDs ) != 1 {
return fmt . Errorf ( "found %d folders, while expecting at most one" , len ( folderUIDs ) )
}
2021-11-30 07:07:04 -06:00
2021-05-11 00:10:19 -05:00
folderID := folderUIDs [ 0 ] . ID
2022-06-13 08:26:17 -05:00
if err := l . requireEditPermissionsOnFolder ( c , signedInUser , folderID ) ; err != nil {
2021-05-11 00:10:19 -05:00
return err
}
var connectionIDs [ ] struct {
ConnectionID int64 ` xorm:"connection_id" `
}
sql := "SELECT lec.connection_id FROM library_element AS le"
2023-02-01 10:32:05 -06:00
sql += " INNER JOIN " + model . LibraryElementConnectionTableName + " AS lec on le.id = lec.element_id"
2021-05-11 00:10:19 -05:00
sql += " WHERE le.folder_id=? AND le.org_id=?"
2023-09-06 04:16:10 -05:00
err = session . SQL ( sql , folderID , signedInUser . GetOrgID ( ) ) . Find ( & connectionIDs )
2021-05-11 00:10:19 -05:00
if err != nil {
return err
}
if len ( connectionIDs ) > 0 {
2023-02-01 10:32:05 -06:00
return model . ErrFolderHasConnectedLibraryElements
2021-05-11 00:10:19 -05:00
}
var elementIDs [ ] struct {
ID int64 ` xorm:"id" `
}
2023-09-06 04:16:10 -05:00
err = session . SQL ( "SELECT id from library_element WHERE folder_id=? AND org_id=?" , folderID , signedInUser . GetOrgID ( ) ) . Find ( & elementIDs )
2021-05-11 00:10:19 -05:00
if err != nil {
return err
}
for _ , elementID := range elementIDs {
2023-02-01 10:32:05 -06:00
_ , err := session . Exec ( "DELETE FROM " + model . LibraryElementConnectionTableName + " WHERE element_id=?" , elementID . ID )
2021-05-11 00:10:19 -05:00
if err != nil {
return err
}
}
2023-09-06 04:16:10 -05:00
if _ , err := session . Exec ( "DELETE FROM library_element WHERE folder_id=? AND org_id=?" , folderID , signedInUser . GetOrgID ( ) ) ; err != nil {
2021-05-11 00:10:19 -05:00
return err
}
return nil
} )
}