17119: Merge branch 'master' into 17119-add-filter-groups
[arvados.git] / lib / controller / localdb / conn.go
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 package localdb
6
7 import (
8         "context"
9         "fmt"
10         "strings"
11
12         "git.arvados.org/arvados.git/lib/controller/railsproxy"
13         "git.arvados.org/arvados.git/lib/controller/rpc"
14         "git.arvados.org/arvados.git/sdk/go/arvados"
15 )
16
17 type railsProxy = rpc.Conn
18
19 type Conn struct {
20         cluster     *arvados.Cluster
21         *railsProxy // handles API methods that aren't defined on Conn itself
22         loginController
23 }
24
25 func NewConn(cluster *arvados.Cluster) *Conn {
26         railsProxy := railsproxy.NewConn(cluster)
27         var conn Conn
28         conn = Conn{
29                 cluster:    cluster,
30                 railsProxy: railsProxy,
31         }
32         conn.loginController = chooseLoginController(cluster, &conn)
33         return &conn
34 }
35
36 // Logout handles the logout of conn giving to the appropriate loginController
37 func (conn *Conn) Logout(ctx context.Context, opts arvados.LogoutOptions) (arvados.LogoutResponse, error) {
38         return conn.loginController.Logout(ctx, opts)
39 }
40
41 // Login handles the login of conn giving to the appropriate loginController
42 func (conn *Conn) Login(ctx context.Context, opts arvados.LoginOptions) (arvados.LoginResponse, error) {
43         return conn.loginController.Login(ctx, opts)
44 }
45
46 // UserAuthenticate handles the User Authentication of conn giving to the appropriate loginController
47 func (conn *Conn) UserAuthenticate(ctx context.Context, opts arvados.UserAuthenticateOptions) (arvados.APIClientAuthorization, error) {
48         return conn.loginController.UserAuthenticate(ctx, opts)
49 }
50
51 func (conn *Conn) GroupContents(ctx context.Context, options arvados.GroupContentsOptions) (arvados.ObjectList, error) {
52         // The requested UUID can be a user (virtual home project), which we just pass on to
53         // the API server.
54         if strings.Index(options.UUID, "-j7d0g-") != 5 {
55                 return conn.railsProxy.GroupContents(ctx, options)
56         }
57
58         var resp arvados.ObjectList
59
60         // Get the group object
61         respGroup, err := conn.GroupGet(ctx, arvados.GetOptions{UUID: options.UUID})
62         if err != nil {
63                 return resp, err
64         }
65
66         // If the group has groupClass 'filter', apply the filters before getting the contents.
67         if respGroup.GroupClass == "filter" {
68                 if filters, ok := respGroup.Properties["filters"].([]interface{}); ok {
69                         for _, f := range filters {
70                                 // f is supposed to be a []string
71                                 tmp, ok2 := f.([]interface{})
72                                 if !ok2 || len(tmp) < 3 {
73                                         return resp, fmt.Errorf("filter unparsable: %T, %+v, original field: %T, %+v\n", tmp, tmp, f, f)
74                                 }
75                                 var filter arvados.Filter
76                                 if attr, ok2 := tmp[0].(string); ok2 {
77                                         filter.Attr = attr
78                                 } else {
79                                         return resp, fmt.Errorf("filter unparsable: attribute must be string: %T, %+v, filter: %T, %+v\n", tmp[0], tmp[0], f, f)
80                                 }
81                                 if operator, ok2 := tmp[1].(string); ok2 {
82                                         filter.Operator = operator
83                                 } else {
84                                         return resp, fmt.Errorf("filter unparsable: operator must be string: %T, %+v, filter: %T, %+v\n", tmp[1], tmp[1], f, f)
85                                 }
86                                 filter.Operand = tmp[2]
87                                 options.Filters = append(options.Filters, filter)
88                         }
89                 } else {
90                         return resp, fmt.Errorf("filter unparsable: not an array\n")
91                 }
92                 // Use the generic /groups/contents endpoint for filter groups
93                 options.UUID = ""
94         }
95
96         return conn.railsProxy.GroupContents(ctx, options)
97 }