From 0d4e6a4a16ec2446270fc591eaddef2b6cf06d38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rn=20Friedrich=20Dreyer?= Date: Wed, 24 Jun 2020 12:59:22 +0200 Subject: [PATCH] initial group api implementation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jörn Friedrich Dreyer --- go.mod | 5 +- go.sum | 32 ++ pkg/proto/v0/accounts.pb.go | 424 ++++++++++++----------- pkg/proto/v0/accounts.pb.micro.go | 60 ++-- pkg/proto/v0/accounts.pb.web.go | 20 +- pkg/proto/v0/accounts.proto | 32 +- pkg/proto/v0/accounts.swagger.json | 530 +++++++++++++---------------- pkg/server/grpc/server.go | 3 + pkg/service/v0/accounts.go | 401 ++++++++++++++++++++++ pkg/service/v0/groups.go | 321 +++++++++++++++++ pkg/service/v0/service.go | 317 +---------------- pkg/service/v0/settings.go | 31 +- 12 files changed, 1314 insertions(+), 862 deletions(-) create mode 100644 pkg/service/v0/accounts.go create mode 100644 pkg/service/v0/groups.go diff --git a/go.mod b/go.mod index 75f8c8e4c..488d7ee5c 100644 --- a/go.mod +++ b/go.mod @@ -21,6 +21,7 @@ require ( github.com/jmhodges/levigo v1.0.0 // indirect github.com/micro/cli/v2 v2.1.2 github.com/micro/go-micro/v2 v2.6.0 + github.com/micro/protoc-gen-micro/v2 v2.3.0 // indirect github.com/oklog/run v1.1.0 github.com/owncloud/ocis-pkg/v2 v2.2.2-0.20200602070144-cd0620668170 github.com/owncloud/ocis-settings v0.0.0-20200522101320-46ea31026363 @@ -30,8 +31,8 @@ require ( github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c // indirect github.com/tredoe/osutil v1.0.5 golang.org/x/net v0.0.0-20200301022130-244492dfa37a - google.golang.org/genproto v0.0.0-20200420144010-e5e8543f8aeb - google.golang.org/protobuf v1.23.0 + google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 + google.golang.org/protobuf v1.25.0 honnef.co/go/tools v0.0.1-2020.1.4 // indirect ) diff --git a/go.sum b/go.sum index 91bbac9cd..dcf2785b0 100644 --- a/go.sum +++ b/go.sum @@ -175,10 +175,13 @@ github.com/cespare/xxhash/v2 v2.1.0 h1:yTUvW7Vhb89inJ+8irsUqiWjh8iT6sQPZiQzI6ReG github.com/cespare/xxhash/v2 v2.1.0/go.mod h1:dgIUBU3pDso/gPgZ1osOZ0iQf77oPR28Tjxl5dIMyVM= github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ= github.com/cheggaaa/pb v1.0.28/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= github.com/cloudflare/cloudflare-go v0.10.2/go.mod h1:qhVI5MKwBGhdNU89ZRz2plgYutcJ5PCekLxXn56w6SY= github.com/cloudflare/cloudflare-go v0.10.6/go.mod h1:dcRl7AXBH5Bf7QFTBVc3TRzwvotSeO4AlnMhuxORAX8= +github.com/cloudflare/cloudflare-go v0.10.9/go.mod h1:5TrsWH+3f4NV6WjtS5QFp+DifH81rph40gU374Sh0dQ= github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko= github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= github.com/containerd/containerd v1.3.0-beta.2.0.20190828155532-0293cbd26c69/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= @@ -252,6 +255,7 @@ github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDD github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/dustin/go-humanize v0.0.0-20180421182945-02af3965c54e/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= @@ -385,6 +389,7 @@ github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:x github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= @@ -400,6 +405,8 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/go-replayers/grpcreplay v0.1.0/go.mod h1:8Ig2Idjpr6gifRd6pNVggX6TC1Zw6Jx74AKp7QNH2QE= @@ -590,12 +597,15 @@ github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-tty v0.0.0-20180219170247-931426f7535a/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= @@ -613,6 +623,7 @@ github.com/micro/go-micro v1.17.1/go.mod h1:klwUJL1gkdY1MHFyz+fFJXn52dKcty4hoe95 github.com/micro/go-micro v1.18.0 h1:gP70EZVHpJuUIT0YWth192JmlIci+qMOEByHm83XE9E= github.com/micro/go-micro v1.18.0/go.mod h1:klwUJL1gkdY1MHFyz+fFJXn52dKcty4hoe95Mp571AA= github.com/micro/go-micro/v2 v2.0.0/go.mod h1:v7QP5UhKRt37ixjJe8DouWmg0/eE6dltr5h0idJ9BpE= +github.com/micro/go-micro/v2 v2.5.1-0.20200417165434-16db76bee2fb/go.mod h1:qz2UT4UFdFVs+qUGMuDK3xuHgude1BgntqQ29sbpPlE= github.com/micro/go-micro/v2 v2.6.0 h1:HH6uEqTu6pkBtAlwAqQW2sf33640iEa1s9puGIctpO0= github.com/micro/go-micro/v2 v2.6.0/go.mod h1:60HMKlDN4ShZDJRrlgdcAmkCWNhQbYv+CDG3r7iLE34= github.com/micro/go-plugins v1.5.1 h1:swcFD7ynCTUo98APqIEIbPu2XMd6yVGTnI8PqdnCwOQ= @@ -620,8 +631,14 @@ github.com/micro/go-plugins v1.5.1/go.mod h1:jcxejzJCAMH731cQHbS/hncyKe0rxAbzKki github.com/micro/go-plugins/wrapper/trace/opencensus/v2 v2.0.1 h1:7IkXfl94MdLZQwk0lNmu9Cg5WP42Zak9EtQMeN4SvVs= github.com/micro/go-plugins/wrapper/trace/opencensus/v2 v2.0.1/go.mod h1:QrkcwcDtIs2hIJpIEhozekyf6Rfz5C36kFI8+zzCpX0= github.com/micro/mdns v0.3.0/go.mod h1:KJ0dW7KmicXU2BV++qkLlmHYcVv7/hHnbtguSWt9Aoc= +github.com/micro/micro v1.16.0 h1:qCZV20WoTOtJ1IyLU/a0A0BMSertfu+iOj/2AJ4Uvrk= github.com/micro/micro v1.16.0/go.mod h1:TO5Ng0KidbfRYIxVM4Q3deZ0A+qwRyP9WeXp+k2fWNA= +github.com/micro/micro/v2 v2.5.1-0.20200418121137-24e9b206767c h1:0xGuo2yepDL8p+id/kXqVka+5iiOBSyfqOX01csnOYk= +github.com/micro/micro/v2 v2.5.1-0.20200418121137-24e9b206767c/go.mod h1:fqqaYbJGYzSBi7Ms2Adly7Xzw9+WIRBAucUjwGmYeFY= +github.com/micro/protoc-gen-micro v1.0.0 h1:qKh5S3I1RfenhIs5mqDFJLwRlRDlgin7XWiUKZbpwLM= github.com/micro/protoc-gen-micro v1.0.0/go.mod h1:C8ij4DJhapBmypcT00AXdb0cZ675/3PqUO02buWWqbE= +github.com/micro/protoc-gen-micro/v2 v2.3.0 h1:PBbGeNh4BOy1w4eRdeo4yWJJNWGLnaJX6/h55I74EXE= +github.com/micro/protoc-gen-micro/v2 v2.3.0/go.mod h1:gcsUvKSTTTalq+pqdUbFS40OTsURpYgL5+yUguR1djk= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.3/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.15/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= @@ -687,6 +704,7 @@ github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/nats-io/stan.go v0.5.0/go.mod h1:dYqB+vMN3C2F9pT1FRQpg9eHbjPj6mP0yYuyBNuXHZE= github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms= +github.com/netdata/go-orchestrator v0.0.0-20190905093727-c793edba0e8f/go.mod h1:ECF8anFVCt/TfTIWVPgPrNaYJXtAtpAOF62ugDbw41A= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nlopes/slack v0.6.0/go.mod h1:JzQ9m3PMAqcpeCam7UaHSuBuupz7CmpjehYMayT6YOk= @@ -706,6 +724,8 @@ github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DV github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/oleiade/reflections v1.0.0/go.mod h1:RbATFBbKYkVdqmSFtx13Bb/tVhR0lgOBXunWTZKeL4w= github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/olekukonko/tablewriter v0.0.3/go.mod h1:YZeBtGzYYEsCHp2LST/u/0NDwGkRoBtmn1cIWCJiS6M= +github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA= github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= @@ -911,6 +931,7 @@ github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGr github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasttemplate v0.0.0-20170224212429-dcecefd839c4 h1:gKMu1Bf6QINDnvyZuTaACm9ofY+PRh+5vFz4oxBZeF8= @@ -1048,9 +1069,11 @@ golang.org/x/net v0.0.0-20191014212845-da9a3fd4c582/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20191027093000-83d349e8ac1a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191028085509-fe3aa8a45271/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191109021931-daa7c04131f5/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191126235420-ef20fe5d7933/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191207000613-e7e4b65ae663/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200301022130-244492dfa37a h1:GuSPYbZzB5/dcLNCwLQLsg3obCJtX9IJhpXkvY7kzk0= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1059,6 +1082,8 @@ golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4Iltr golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6 h1:pE8b58s1HRDMi8RDc79m0HISf9D4TzseP40cEA6IGfs= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1192,6 +1217,8 @@ google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvx google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200420144010-e5e8543f8aeb h1:nAFaltAMbNVA0rixtwvdnqgSVLX3HFUUvMkEklmzbYM= google.golang.org/genproto v0.0.0-20200420144010-e5e8543f8aeb/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/grpc v1.26.0 h1:2dTRdpdFEEhJYQD8EMLB61nnrzSCTbG38PhqdhvOltg= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= @@ -1199,8 +1226,12 @@ google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= gopkg.in/DataDog/dd-trace-go.v1 v1.19.0/go.mod h1:DVp8HmDh8PuTu2Z0fVVlBsyWaC++fzwVCaGWylTe3tg= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= @@ -1236,6 +1267,7 @@ gopkg.in/ldap.v2 v2.5.1/go.mod h1:oI0cpe/D7HRtBQl8aTg+ZmzFUAvu4lsv3eLXMLGFxWk= gopkg.in/ldap.v3 v3.1.0/go.mod h1:dQjCc0R0kfyFjIlWNMH1DORwUASZyDxo2Ry1B51dXaQ= gopkg.in/ns1/ns1-go.v2 v2.0.0-20190730140822-b51389932cbc/go.mod h1:VV+3haRsgDiVLxyifmMBrBIuCWFBPYKbRssXB9z67Hw= gopkg.in/olivere/elastic.v5 v5.0.82/go.mod h1:uhHoB4o3bvX5sorxBU29rPcmBQdV2Qfg0FBrx5D6pV0= +gopkg.in/olivere/elastic.v5 v5.0.83/go.mod h1:LXF6q9XNBxpMqrcgax95C6xyARXWbbCXUrtTxrNrxJI= gopkg.in/redis.v3 v3.6.4/go.mod h1:6XeGv/CrsUFDU9aVbUdNykN7k1zVmoeg83KC9RbQfiU= gopkg.in/resty.v1 v1.9.1/go.mod h1:vo52Hzryw9PnPHcJfPsBiFW62XhNx5OczbV9y+IMpgc= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= diff --git a/pkg/proto/v0/accounts.pb.go b/pkg/proto/v0/accounts.pb.go index 5020875e8..c75bb6b2f 100644 --- a/pkg/proto/v0/accounts.pb.go +++ b/pkg/proto/v0/accounts.pb.go @@ -1248,8 +1248,10 @@ type AddMemberRequest struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields + // The id of the group to add a member to + GroupId string `protobuf:"bytes,1,opt,name=group_id,json=groupId,proto3" json:"group_id,omitempty"` // The account id to add - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + AccountId string `protobuf:"bytes,2,opt,name=account_id,json=accountId,proto3" json:"account_id,omitempty"` } func (x *AddMemberRequest) Reset() { @@ -1284,9 +1286,16 @@ func (*AddMemberRequest) Descriptor() ([]byte, []int) { return file_accounts_proto_rawDescGZIP(), []int{15} } -func (x *AddMemberRequest) GetId() string { +func (x *AddMemberRequest) GetGroupId() string { if x != nil { - return x.Id + return x.GroupId + } + return "" +} + +func (x *AddMemberRequest) GetAccountId() string { + if x != nil { + return x.AccountId } return "" } @@ -1296,8 +1305,8 @@ type RemoveMemberRequest struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // The group id - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + // The id of the group to remove a member from + GroupId string `protobuf:"bytes,1,opt,name=group_id,json=groupId,proto3" json:"group_id,omitempty"` // The account id to remove AccountId string `protobuf:"bytes,2,opt,name=account_id,json=accountId,proto3" json:"account_id,omitempty"` } @@ -1334,9 +1343,9 @@ func (*RemoveMemberRequest) Descriptor() ([]byte, []int) { return file_accounts_proto_rawDescGZIP(), []int{16} } -func (x *RemoveMemberRequest) GetId() string { +func (x *RemoveMemberRequest) GetGroupId() string { if x != nil { - return x.Id + return x.GroupId } return "" } @@ -1379,7 +1388,7 @@ type ListMembersRequest struct { // * Query `display_name=\\"Test String\\"` returns groups with // display names that include both "Test" and "String" Query string `protobuf:"bytes,4,opt,name=query,proto3" json:"query,omitempty"` - // The group id + // The id of the group to list members from Id string `protobuf:"bytes,5,opt,name=id,proto3" json:"id,omitempty"` } @@ -2047,207 +2056,214 @@ var file_accounts_proto_rawDesc = []byte{ 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x61, 0x73, 0x6b, 0x22, 0x24, 0x0a, 0x12, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, - 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x22, + 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x4c, 0x0a, 0x10, 0x41, 0x64, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, - 0x69, 0x64, 0x22, 0x44, 0x0a, 0x13, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x4d, 0x65, 0x6d, 0x62, - 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x61, 0x63, 0x63, - 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, - 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x64, 0x22, 0xc0, 0x01, 0x0a, 0x12, 0x4c, 0x69, 0x73, - 0x74, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x20, 0x0a, 0x09, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x05, 0x42, 0x03, 0xe0, 0x41, 0x01, 0x52, 0x08, 0x70, 0x61, 0x67, 0x65, 0x53, 0x69, 0x7a, - 0x65, 0x12, 0x22, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x03, 0xe0, 0x41, 0x01, 0x52, 0x09, 0x70, 0x61, 0x67, 0x65, - 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x39, 0x0a, 0x0a, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x6d, - 0x61, 0x73, 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, - 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x52, 0x09, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, - 0x12, 0x19, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, - 0x03, 0xe0, 0x41, 0x01, 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x12, 0x0e, 0x0a, 0x02, 0x69, - 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x6a, 0x0a, 0x13, 0x4c, - 0x69, 0x73, 0x74, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x2b, 0x0a, 0x07, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x41, - 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x07, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x12, - 0x26, 0x0a, 0x0f, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f, 0x6b, - 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, - 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0xea, 0x08, 0x0a, 0x05, 0x47, 0x72, 0x6f, 0x75, - 0x70, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, - 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x6e, 0x61, 0x6d, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, - 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2b, 0x0a, 0x07, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, - 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, - 0x2e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x07, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, - 0x73, 0x12, 0x29, 0x0a, 0x06, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x11, 0x2e, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x41, 0x63, 0x63, - 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x06, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x73, 0x12, 0x20, 0x0a, 0x0b, - 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1d, - 0x0a, 0x0a, 0x67, 0x69, 0x64, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x06, 0x20, 0x01, - 0x28, 0x03, 0x52, 0x09, 0x67, 0x69, 0x64, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x46, 0x0a, - 0x11, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, - 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, - 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, - 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x44, 0x61, 0x74, - 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x46, 0x0a, 0x11, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, - 0x5f, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, + 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x64, 0x12, 0x1d, 0x0a, + 0x0a, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x09, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x64, 0x22, 0x4f, 0x0a, 0x13, + 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x64, 0x12, 0x1d, + 0x0a, 0x0a, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x09, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x64, 0x22, 0xc0, 0x01, + 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x09, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x73, 0x69, 0x7a, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x42, 0x03, 0xe0, 0x41, 0x01, 0x52, 0x08, 0x70, 0x61, + 0x67, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x22, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, + 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x03, 0xe0, 0x41, 0x01, 0x52, + 0x09, 0x70, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x39, 0x0a, 0x0a, 0x66, 0x69, + 0x65, 0x6c, 0x64, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x52, 0x09, 0x66, 0x69, 0x65, 0x6c, + 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x12, 0x19, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x09, 0x42, 0x03, 0xe0, 0x41, 0x01, 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, + 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, + 0x22, 0x6a, 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2b, 0x0a, 0x07, 0x6d, 0x65, 0x6d, 0x62, 0x65, + 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x73, 0x65, 0x74, 0x74, 0x69, + 0x6e, 0x67, 0x73, 0x2e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x07, 0x6d, 0x65, 0x6d, + 0x62, 0x65, 0x72, 0x73, 0x12, 0x26, 0x0a, 0x0f, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x70, 0x61, 0x67, + 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6e, + 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0xea, 0x08, 0x0a, + 0x05, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, + 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x69, + 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2b, 0x0a, 0x07, 0x6d, 0x65, 0x6d, + 0x62, 0x65, 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x73, 0x65, 0x74, + 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x07, 0x6d, + 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x12, 0x29, 0x0a, 0x06, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x73, + 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, + 0x73, 0x2e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x06, 0x6f, 0x77, 0x6e, 0x65, 0x72, + 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x67, 0x69, 0x64, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, + 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x67, 0x69, 0x64, 0x4e, 0x75, 0x6d, 0x62, + 0x65, 0x72, 0x12, 0x46, 0x0a, 0x11, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x64, 0x61, + 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0f, 0x63, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x64, 0x44, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x46, 0x0a, 0x11, 0x64, 0x65, + 0x6c, 0x65, 0x74, 0x65, 0x64, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, + 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x52, 0x0f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x44, 0x61, 0x74, 0x65, 0x54, 0x69, + 0x6d, 0x65, 0x12, 0x4c, 0x0a, 0x14, 0x65, 0x78, 0x70, 0x69, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x5f, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0f, 0x64, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x64, 0x44, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x4c, 0x0a, - 0x14, 0x65, 0x78, 0x70, 0x69, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x64, 0x61, 0x74, 0x65, - 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, - 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x12, 0x65, 0x78, 0x70, 0x69, 0x72, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x44, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x35, 0x0a, 0x17, 0x68, - 0x69, 0x64, 0x65, 0x5f, 0x66, 0x72, 0x6f, 0x6d, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x14, 0x68, 0x69, - 0x64, 0x65, 0x46, 0x72, 0x6f, 0x6d, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, - 0x74, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x76, 0x69, 0x73, 0x69, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, - 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x76, 0x69, 0x73, 0x69, 0x62, 0x69, 0x6c, 0x69, - 0x74, 0x79, 0x12, 0x37, 0x0a, 0x18, 0x6f, 0x6e, 0x5f, 0x70, 0x72, 0x65, 0x6d, 0x69, 0x73, 0x65, - 0x73, 0x5f, 0x73, 0x79, 0x6e, 0x63, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x14, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x15, 0x6f, 0x6e, 0x50, 0x72, 0x65, 0x6d, 0x69, 0x73, 0x65, 0x73, - 0x53, 0x79, 0x6e, 0x63, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x37, 0x0a, 0x18, 0x6f, - 0x6e, 0x5f, 0x70, 0x72, 0x65, 0x6d, 0x69, 0x73, 0x65, 0x73, 0x5f, 0x69, 0x6d, 0x6d, 0x75, 0x74, - 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x15, 0x20, 0x01, 0x28, 0x09, 0x52, 0x15, 0x6f, - 0x6e, 0x50, 0x72, 0x65, 0x6d, 0x69, 0x73, 0x65, 0x73, 0x49, 0x6d, 0x6d, 0x75, 0x74, 0x61, 0x62, - 0x6c, 0x65, 0x49, 0x64, 0x12, 0x45, 0x0a, 0x1f, 0x6f, 0x6e, 0x5f, 0x70, 0x72, 0x65, 0x6d, 0x69, - 0x73, 0x65, 0x73, 0x5f, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x5f, 0x69, 0x64, 0x65, - 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x18, 0x16, 0x20, 0x01, 0x28, 0x09, 0x52, 0x1c, 0x6f, - 0x6e, 0x50, 0x72, 0x65, 0x6d, 0x69, 0x73, 0x65, 0x73, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, - 0x79, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x43, 0x0a, 0x1e, 0x6f, - 0x6e, 0x5f, 0x70, 0x72, 0x65, 0x6d, 0x69, 0x73, 0x65, 0x73, 0x5f, 0x64, 0x69, 0x73, 0x74, 0x69, - 0x6e, 0x67, 0x75, 0x69, 0x73, 0x68, 0x65, 0x64, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x17, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x1b, 0x6f, 0x6e, 0x50, 0x72, 0x65, 0x6d, 0x69, 0x73, 0x65, 0x73, 0x44, - 0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x75, 0x69, 0x73, 0x68, 0x65, 0x64, 0x4e, 0x61, 0x6d, 0x65, - 0x12, 0x3e, 0x0a, 0x1c, 0x6f, 0x6e, 0x5f, 0x70, 0x72, 0x65, 0x6d, 0x69, 0x73, 0x65, 0x73, 0x5f, - 0x73, 0x61, 0x6d, 0x5f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, - 0x18, 0x18, 0x20, 0x01, 0x28, 0x09, 0x52, 0x18, 0x6f, 0x6e, 0x50, 0x72, 0x65, 0x6d, 0x69, 0x73, - 0x65, 0x73, 0x53, 0x61, 0x6d, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x4e, 0x61, 0x6d, 0x65, - 0x12, 0x35, 0x0a, 0x17, 0x6f, 0x6e, 0x5f, 0x70, 0x72, 0x65, 0x6d, 0x69, 0x73, 0x65, 0x73, 0x5f, - 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x19, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x14, 0x6f, 0x6e, 0x50, 0x72, 0x65, 0x6d, 0x69, 0x73, 0x65, 0x73, 0x44, 0x6f, 0x6d, - 0x61, 0x69, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x38, 0x0a, 0x19, 0x6f, 0x6e, 0x5f, 0x70, 0x72, - 0x65, 0x6d, 0x69, 0x73, 0x65, 0x73, 0x5f, 0x6e, 0x65, 0x74, 0x5f, 0x62, 0x69, 0x6f, 0x73, 0x5f, - 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x1a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x15, 0x6f, 0x6e, 0x50, 0x72, - 0x65, 0x6d, 0x69, 0x73, 0x65, 0x73, 0x4e, 0x65, 0x74, 0x42, 0x69, 0x6f, 0x73, 0x4e, 0x61, 0x6d, - 0x65, 0x12, 0x43, 0x0a, 0x1f, 0x6f, 0x6e, 0x5f, 0x70, 0x72, 0x65, 0x6d, 0x69, 0x73, 0x65, 0x73, - 0x5f, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x73, 0x79, 0x6e, 0x63, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x5f, - 0x74, 0x69, 0x6d, 0x65, 0x18, 0x1b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x1a, 0x6f, 0x6e, 0x50, 0x72, - 0x65, 0x6d, 0x69, 0x73, 0x65, 0x73, 0x4c, 0x61, 0x73, 0x74, 0x53, 0x79, 0x6e, 0x63, 0x44, 0x61, - 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x6c, 0x0a, 0x1f, 0x6f, 0x6e, 0x5f, 0x70, 0x72, 0x65, - 0x6d, 0x69, 0x73, 0x65, 0x73, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x69, - 0x6e, 0x67, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x18, 0x1c, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x25, 0x2e, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x4f, 0x6e, 0x50, 0x72, 0x65, - 0x6d, 0x69, 0x73, 0x65, 0x73, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x69, 0x6e, - 0x67, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x1c, 0x6f, 0x6e, 0x50, 0x72, 0x65, 0x6d, 0x69, 0x73, - 0x65, 0x73, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x69, 0x6e, 0x67, 0x45, 0x72, - 0x72, 0x6f, 0x72, 0x73, 0x22, 0xcf, 0x01, 0x0a, 0x1b, 0x4f, 0x6e, 0x50, 0x72, 0x65, 0x6d, 0x69, - 0x73, 0x65, 0x73, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x69, 0x6e, 0x67, 0x45, - 0x72, 0x72, 0x6f, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, - 0x12, 0x48, 0x0a, 0x12, 0x6f, 0x63, 0x63, 0x75, 0x72, 0x72, 0x65, 0x64, 0x5f, 0x64, 0x61, 0x74, - 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, - 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, - 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x10, 0x6f, 0x63, 0x63, 0x75, 0x72, 0x72, - 0x65, 0x64, 0x44, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x34, 0x0a, 0x16, 0x70, 0x72, - 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x5f, 0x63, 0x61, 0x75, 0x73, 0x69, 0x6e, 0x67, 0x5f, 0x65, - 0x72, 0x72, 0x6f, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x14, 0x70, 0x72, 0x6f, 0x70, - 0x65, 0x72, 0x74, 0x79, 0x43, 0x61, 0x75, 0x73, 0x69, 0x6e, 0x67, 0x45, 0x72, 0x72, 0x6f, 0x72, - 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x32, 0xcb, 0x04, 0x0a, 0x0f, 0x41, 0x63, 0x63, 0x6f, 0x75, - 0x6e, 0x74, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x78, 0x0a, 0x0c, 0x4c, 0x69, - 0x73, 0x74, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x12, 0x1d, 0x2e, 0x73, 0x65, 0x74, - 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, - 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x73, 0x65, 0x74, 0x74, - 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x29, 0x82, 0xd3, 0xe4, 0x93, 0x02, - 0x23, 0x22, 0x1e, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x30, 0x2f, 0x61, 0x63, 0x63, 0x6f, 0x75, - 0x6e, 0x74, 0x73, 0x2f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2d, 0x6c, 0x69, 0x73, - 0x74, 0x3a, 0x01, 0x2a, 0x12, 0x66, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x41, 0x63, 0x63, 0x6f, 0x75, - 0x6e, 0x74, 0x12, 0x1b, 0x2e, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x47, 0x65, - 0x74, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x11, 0x2e, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x41, 0x63, 0x63, 0x6f, 0x75, - 0x6e, 0x74, 0x22, 0x28, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x22, 0x22, 0x1d, 0x2f, 0x61, 0x70, 0x69, - 0x2f, 0x76, 0x30, 0x2f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2f, 0x61, 0x63, 0x63, - 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2d, 0x67, 0x65, 0x74, 0x3a, 0x01, 0x2a, 0x12, 0x6f, 0x0a, 0x0d, - 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1e, 0x2e, - 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, - 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, - 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, - 0x22, 0x2b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x25, 0x22, 0x20, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, - 0x30, 0x2f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2f, 0x61, 0x63, 0x63, 0x6f, 0x75, - 0x6e, 0x74, 0x73, 0x2d, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x3a, 0x01, 0x2a, 0x12, 0x6f, 0x0a, - 0x0d, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1e, - 0x2e, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, - 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x11, - 0x2e, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, - 0x74, 0x22, 0x2b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x25, 0x22, 0x20, 0x2f, 0x61, 0x70, 0x69, 0x2f, - 0x76, 0x30, 0x2f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2f, 0x61, 0x63, 0x63, 0x6f, - 0x75, 0x6e, 0x74, 0x73, 0x2d, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x01, 0x2a, 0x12, 0x74, - 0x0a, 0x0d, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, - 0x1e, 0x2e, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, - 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x2b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x25, 0x22, - 0x20, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x30, 0x2f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, - 0x73, 0x2f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2d, 0x64, 0x65, 0x6c, 0x65, 0x74, - 0x65, 0x3a, 0x01, 0x2a, 0x32, 0xac, 0x06, 0x0a, 0x0d, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x53, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x5b, 0x0a, 0x0a, 0x4c, 0x69, 0x73, 0x74, 0x47, 0x72, - 0x6f, 0x75, 0x70, 0x73, 0x12, 0x1b, 0x2e, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, - 0x4c, 0x69, 0x73, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x1c, 0x2e, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x4c, 0x69, 0x73, - 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x12, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0c, 0x12, 0x0a, 0x2f, 0x76, 0x30, 0x2f, 0x67, 0x72, 0x6f, - 0x75, 0x70, 0x73, 0x12, 0x51, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, - 0x19, 0x2e, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x47, 0x72, - 0x6f, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0f, 0x2e, 0x73, 0x65, 0x74, - 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x22, 0x19, 0x82, 0xd3, 0xe4, - 0x93, 0x02, 0x13, 0x12, 0x11, 0x2f, 0x76, 0x30, 0x2f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x2f, - 0x7b, 0x69, 0x64, 0x3d, 0x2a, 0x7d, 0x12, 0x57, 0x0a, 0x0b, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x1c, 0x2e, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, - 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x0f, 0x2e, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x47, - 0x72, 0x6f, 0x75, 0x70, 0x22, 0x19, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x22, 0x0a, 0x2f, 0x76, - 0x30, 0x2f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x3a, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x12, - 0x64, 0x0a, 0x0b, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x1c, - 0x2e, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, - 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0f, 0x2e, 0x73, - 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x22, 0x26, 0x82, - 0xd3, 0xe4, 0x93, 0x02, 0x20, 0x32, 0x17, 0x2f, 0x76, 0x30, 0x2f, 0x67, 0x72, 0x6f, 0x75, 0x70, - 0x73, 0x2f, 0x7b, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x2e, 0x69, 0x64, 0x3d, 0x2a, 0x7d, 0x3a, 0x05, - 0x67, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x5e, 0x0a, 0x0b, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x47, - 0x72, 0x6f, 0x75, 0x70, 0x12, 0x1c, 0x2e, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, - 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x19, 0x82, 0xd3, 0xe4, 0x93, - 0x02, 0x13, 0x2a, 0x11, 0x2f, 0x76, 0x30, 0x2f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x2f, 0x7b, - 0x69, 0x64, 0x3d, 0x2a, 0x7d, 0x12, 0x63, 0x0a, 0x09, 0x41, 0x64, 0x64, 0x4d, 0x65, 0x6d, 0x62, + 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x12, 0x65, 0x78, + 0x70, 0x69, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, + 0x12, 0x35, 0x0a, 0x17, 0x68, 0x69, 0x64, 0x65, 0x5f, 0x66, 0x72, 0x6f, 0x6d, 0x5f, 0x61, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x14, 0x68, 0x69, 0x64, 0x65, 0x46, 0x72, 0x6f, 0x6d, 0x41, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x76, 0x69, 0x73, 0x69, 0x62, + 0x69, 0x6c, 0x69, 0x74, 0x79, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x76, 0x69, 0x73, + 0x69, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x12, 0x37, 0x0a, 0x18, 0x6f, 0x6e, 0x5f, 0x70, 0x72, + 0x65, 0x6d, 0x69, 0x73, 0x65, 0x73, 0x5f, 0x73, 0x79, 0x6e, 0x63, 0x5f, 0x65, 0x6e, 0x61, 0x62, + 0x6c, 0x65, 0x64, 0x18, 0x14, 0x20, 0x01, 0x28, 0x08, 0x52, 0x15, 0x6f, 0x6e, 0x50, 0x72, 0x65, + 0x6d, 0x69, 0x73, 0x65, 0x73, 0x53, 0x79, 0x6e, 0x63, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, + 0x12, 0x37, 0x0a, 0x18, 0x6f, 0x6e, 0x5f, 0x70, 0x72, 0x65, 0x6d, 0x69, 0x73, 0x65, 0x73, 0x5f, + 0x69, 0x6d, 0x6d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x15, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x15, 0x6f, 0x6e, 0x50, 0x72, 0x65, 0x6d, 0x69, 0x73, 0x65, 0x73, 0x49, 0x6d, + 0x6d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x49, 0x64, 0x12, 0x45, 0x0a, 0x1f, 0x6f, 0x6e, 0x5f, + 0x70, 0x72, 0x65, 0x6d, 0x69, 0x73, 0x65, 0x73, 0x5f, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, + 0x79, 0x5f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x18, 0x16, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x1c, 0x6f, 0x6e, 0x50, 0x72, 0x65, 0x6d, 0x69, 0x73, 0x65, 0x73, 0x53, 0x65, + 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, + 0x12, 0x43, 0x0a, 0x1e, 0x6f, 0x6e, 0x5f, 0x70, 0x72, 0x65, 0x6d, 0x69, 0x73, 0x65, 0x73, 0x5f, + 0x64, 0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x75, 0x69, 0x73, 0x68, 0x65, 0x64, 0x5f, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x17, 0x20, 0x01, 0x28, 0x09, 0x52, 0x1b, 0x6f, 0x6e, 0x50, 0x72, 0x65, 0x6d, + 0x69, 0x73, 0x65, 0x73, 0x44, 0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x75, 0x69, 0x73, 0x68, 0x65, + 0x64, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x3e, 0x0a, 0x1c, 0x6f, 0x6e, 0x5f, 0x70, 0x72, 0x65, 0x6d, + 0x69, 0x73, 0x65, 0x73, 0x5f, 0x73, 0x61, 0x6d, 0x5f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, + 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x18, 0x20, 0x01, 0x28, 0x09, 0x52, 0x18, 0x6f, 0x6e, 0x50, + 0x72, 0x65, 0x6d, 0x69, 0x73, 0x65, 0x73, 0x53, 0x61, 0x6d, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, + 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x35, 0x0a, 0x17, 0x6f, 0x6e, 0x5f, 0x70, 0x72, 0x65, 0x6d, + 0x69, 0x73, 0x65, 0x73, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, + 0x18, 0x19, 0x20, 0x01, 0x28, 0x09, 0x52, 0x14, 0x6f, 0x6e, 0x50, 0x72, 0x65, 0x6d, 0x69, 0x73, + 0x65, 0x73, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x38, 0x0a, 0x19, + 0x6f, 0x6e, 0x5f, 0x70, 0x72, 0x65, 0x6d, 0x69, 0x73, 0x65, 0x73, 0x5f, 0x6e, 0x65, 0x74, 0x5f, + 0x62, 0x69, 0x6f, 0x73, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x1a, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x15, 0x6f, 0x6e, 0x50, 0x72, 0x65, 0x6d, 0x69, 0x73, 0x65, 0x73, 0x4e, 0x65, 0x74, 0x42, 0x69, + 0x6f, 0x73, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x43, 0x0a, 0x1f, 0x6f, 0x6e, 0x5f, 0x70, 0x72, 0x65, + 0x6d, 0x69, 0x73, 0x65, 0x73, 0x5f, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x73, 0x79, 0x6e, 0x63, 0x5f, + 0x64, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x1b, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x1a, 0x6f, 0x6e, 0x50, 0x72, 0x65, 0x6d, 0x69, 0x73, 0x65, 0x73, 0x4c, 0x61, 0x73, 0x74, 0x53, + 0x79, 0x6e, 0x63, 0x44, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x6c, 0x0a, 0x1f, 0x6f, + 0x6e, 0x5f, 0x70, 0x72, 0x65, 0x6d, 0x69, 0x73, 0x65, 0x73, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x69, + 0x73, 0x69, 0x6f, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x18, 0x1c, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, + 0x4f, 0x6e, 0x50, 0x72, 0x65, 0x6d, 0x69, 0x73, 0x65, 0x73, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, + 0x69, 0x6f, 0x6e, 0x69, 0x6e, 0x67, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x1c, 0x6f, 0x6e, 0x50, + 0x72, 0x65, 0x6d, 0x69, 0x73, 0x65, 0x73, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, + 0x69, 0x6e, 0x67, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x22, 0xcf, 0x01, 0x0a, 0x1b, 0x4f, 0x6e, + 0x50, 0x72, 0x65, 0x6d, 0x69, 0x73, 0x65, 0x73, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, + 0x6e, 0x69, 0x6e, 0x67, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x61, 0x74, + 0x65, 0x67, 0x6f, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x61, 0x74, + 0x65, 0x67, 0x6f, 0x72, 0x79, 0x12, 0x48, 0x0a, 0x12, 0x6f, 0x63, 0x63, 0x75, 0x72, 0x72, 0x65, + 0x64, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x10, 0x6f, + 0x63, 0x63, 0x75, 0x72, 0x72, 0x65, 0x64, 0x44, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, + 0x34, 0x0a, 0x16, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x5f, 0x63, 0x61, 0x75, 0x73, + 0x69, 0x6e, 0x67, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x14, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x43, 0x61, 0x75, 0x73, 0x69, 0x6e, 0x67, + 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x32, 0xcb, 0x04, 0x0a, 0x0f, + 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, + 0x78, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x12, + 0x1d, 0x2e, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, + 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, + 0x2e, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x63, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x29, + 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x23, 0x22, 0x1e, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x30, 0x2f, + 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, + 0x73, 0x2d, 0x6c, 0x69, 0x73, 0x74, 0x3a, 0x01, 0x2a, 0x12, 0x66, 0x0a, 0x0a, 0x47, 0x65, 0x74, + 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1b, 0x2e, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, + 0x67, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, + 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x28, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x22, 0x22, + 0x1d, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x30, 0x2f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, + 0x73, 0x2f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2d, 0x67, 0x65, 0x74, 0x3a, 0x01, + 0x2a, 0x12, 0x6f, 0x0a, 0x0d, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, + 0x6e, 0x74, 0x12, 0x1e, 0x2e, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x43, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x41, 0x63, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x2b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x25, 0x22, 0x20, 0x2f, + 0x61, 0x70, 0x69, 0x2f, 0x76, 0x30, 0x2f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2f, + 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2d, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x3a, + 0x01, 0x2a, 0x12, 0x6f, 0x0a, 0x0d, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x63, 0x63, 0x6f, + 0x75, 0x6e, 0x74, 0x12, 0x1e, 0x2e, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x41, + 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x2b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x25, 0x22, 0x20, + 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x30, 0x2f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, + 0x2f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2d, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x3a, 0x01, 0x2a, 0x12, 0x74, 0x0a, 0x0d, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x63, 0x63, + 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1e, 0x2e, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, + 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x2b, 0x82, 0xd3, + 0xe4, 0x93, 0x02, 0x25, 0x22, 0x20, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x30, 0x2f, 0x61, 0x63, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2d, + 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x3a, 0x01, 0x2a, 0x32, 0xf3, 0x06, 0x0a, 0x0d, 0x47, 0x72, + 0x6f, 0x75, 0x70, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x6e, 0x0a, 0x0a, 0x4c, + 0x69, 0x73, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x12, 0x1b, 0x2e, 0x73, 0x65, 0x74, 0x74, + 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, + 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x25, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1f, 0x22, 0x1a, 0x2f, 0x61, + 0x70, 0x69, 0x2f, 0x76, 0x30, 0x2f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x2f, 0x67, 0x72, 0x6f, + 0x75, 0x70, 0x73, 0x2d, 0x6c, 0x69, 0x73, 0x74, 0x3a, 0x01, 0x2a, 0x12, 0x5c, 0x0a, 0x08, 0x47, + 0x65, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x19, 0x2e, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, + 0x67, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x0f, 0x2e, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x47, 0x72, + 0x6f, 0x75, 0x70, 0x22, 0x24, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1e, 0x22, 0x19, 0x2f, 0x61, 0x70, + 0x69, 0x2f, 0x76, 0x30, 0x2f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x2f, 0x67, 0x72, 0x6f, 0x75, + 0x70, 0x73, 0x2d, 0x67, 0x65, 0x74, 0x3a, 0x01, 0x2a, 0x12, 0x65, 0x0a, 0x0b, 0x43, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x1c, 0x2e, 0x73, 0x65, 0x74, 0x74, 0x69, + 0x6e, 0x67, 0x73, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0f, 0x2e, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, + 0x73, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x22, 0x27, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x21, 0x22, + 0x1c, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x30, 0x2f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x2f, + 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x2d, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x3a, 0x01, 0x2a, + 0x12, 0x65, 0x0a, 0x0b, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, + 0x1c, 0x2e, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0f, 0x2e, + 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x22, 0x27, + 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x21, 0x22, 0x1c, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x30, 0x2f, + 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x2f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x2d, 0x75, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x3a, 0x01, 0x2a, 0x12, 0x6c, 0x0a, 0x0b, 0x44, 0x65, 0x6c, 0x65, 0x74, + 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x1c, 0x2e, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, + 0x73, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x27, 0x82, 0xd3, + 0xe4, 0x93, 0x02, 0x21, 0x22, 0x1c, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x30, 0x2f, 0x67, 0x72, + 0x6f, 0x75, 0x70, 0x73, 0x2f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x2d, 0x64, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x3a, 0x01, 0x2a, 0x12, 0x69, 0x0a, 0x09, 0x41, 0x64, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x1a, 0x2e, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x41, 0x64, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0f, 0x2e, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x22, - 0x29, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x23, 0x22, 0x1e, 0x2f, 0x76, 0x30, 0x2f, 0x67, 0x72, 0x6f, - 0x75, 0x70, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x3d, 0x2a, 0x7d, 0x2f, 0x6d, 0x65, 0x6d, 0x62, 0x65, - 0x72, 0x73, 0x2f, 0x24, 0x72, 0x65, 0x66, 0x3a, 0x01, 0x2a, 0x12, 0x73, 0x0a, 0x0c, 0x52, 0x65, - 0x6d, 0x6f, 0x76, 0x65, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x1d, 0x2e, 0x73, 0x65, 0x74, - 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x4d, 0x65, 0x6d, 0x62, - 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0f, 0x2e, 0x73, 0x65, 0x74, 0x74, - 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x22, 0x33, 0x82, 0xd3, 0xe4, 0x93, - 0x02, 0x2d, 0x2a, 0x2b, 0x2f, 0x76, 0x30, 0x2f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x2f, 0x7b, - 0x69, 0x64, 0x3d, 0x2a, 0x7d, 0x2f, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x2f, 0x7b, 0x61, - 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x24, 0x72, 0x65, 0x66, 0x12, - 0x72, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x12, 0x1c, - 0x2e, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x65, - 0x6d, 0x62, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x73, - 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x65, 0x6d, 0x62, - 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x26, 0x82, 0xd3, 0xe4, - 0x93, 0x02, 0x20, 0x12, 0x1e, 0x2f, 0x76, 0x30, 0x2f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x2f, - 0x7b, 0x69, 0x64, 0x3d, 0x2a, 0x7d, 0x2f, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x2f, 0x24, - 0x72, 0x65, 0x66, 0x42, 0x14, 0x5a, 0x12, 0x70, 0x6b, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x2f, 0x76, 0x30, 0x3b, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x33, + 0x2f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x29, 0x22, 0x24, 0x2f, 0x76, 0x30, 0x2f, 0x67, 0x72, 0x6f, + 0x75, 0x70, 0x73, 0x2f, 0x7b, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x69, 0x64, 0x3d, 0x2a, 0x7d, + 0x2f, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x2f, 0x24, 0x72, 0x65, 0x66, 0x3a, 0x01, 0x2a, + 0x12, 0x79, 0x0a, 0x0c, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, + 0x12, 0x1d, 0x2e, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x52, 0x65, 0x6d, 0x6f, + 0x76, 0x65, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x0f, 0x2e, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, + 0x22, 0x39, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x33, 0x2a, 0x31, 0x2f, 0x76, 0x30, 0x2f, 0x67, 0x72, + 0x6f, 0x75, 0x70, 0x73, 0x2f, 0x7b, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x69, 0x64, 0x3d, 0x2a, + 0x7d, 0x2f, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x2f, 0x7b, 0x61, 0x63, 0x63, 0x6f, 0x75, + 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x24, 0x72, 0x65, 0x66, 0x12, 0x72, 0x0a, 0x0b, 0x4c, + 0x69, 0x73, 0x74, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x12, 0x1c, 0x2e, 0x73, 0x65, 0x74, + 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x73, 0x65, 0x74, 0x74, 0x69, + 0x6e, 0x67, 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x26, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x20, 0x12, + 0x1e, 0x2f, 0x76, 0x30, 0x2f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x3d, + 0x2a, 0x7d, 0x2f, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x2f, 0x24, 0x72, 0x65, 0x66, 0x42, + 0x14, 0x5a, 0x12, 0x70, 0x6b, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x76, 0x30, 0x3b, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/pkg/proto/v0/accounts.pb.micro.go b/pkg/proto/v0/accounts.pb.micro.go index bc03e6b6b..0a47f58d0 100644 --- a/pkg/proto/v0/accounts.pb.micro.go +++ b/pkg/proto/v0/accounts.pb.micro.go @@ -251,47 +251,49 @@ func NewGroupsServiceEndpoints() []*api.Endpoint { return []*api.Endpoint{ &api.Endpoint{ Name: "GroupsService.ListGroups", - Path: []string{"/v0/groups"}, - Method: []string{"GET"}, + Path: []string{"/api/v0/groups/groups-list"}, + Method: []string{"POST"}, + Body: "*", Handler: "rpc", }, &api.Endpoint{ Name: "GroupsService.GetGroup", - Path: []string{"/v0/groups/{id=*}"}, - Method: []string{"GET"}, + Path: []string{"/api/v0/groups/groups-get"}, + Method: []string{"POST"}, + Body: "*", Handler: "rpc", }, &api.Endpoint{ Name: "GroupsService.CreateGroup", - Path: []string{"/v0/groups"}, + Path: []string{"/api/v0/groups/groups-create"}, Method: []string{"POST"}, - Body: "group", + Body: "*", Handler: "rpc", }, &api.Endpoint{ Name: "GroupsService.UpdateGroup", - Path: []string{"/v0/groups/{group.id=*}"}, - Method: []string{"PATCH"}, - Body: "group", + Path: []string{"/api/v0/groups/groups-update"}, + Method: []string{"POST"}, + Body: "*", Handler: "rpc", }, &api.Endpoint{ Name: "GroupsService.DeleteGroup", - Path: []string{"/v0/groups/{id=*}"}, - Method: []string{"DELETE"}, - Body: "", + Path: []string{"/api/v0/groups/groups-delete"}, + Method: []string{"POST"}, + Body: "*", Handler: "rpc", }, &api.Endpoint{ Name: "GroupsService.AddMember", - Path: []string{"/v0/groups/{id=*}/members/$ref"}, + Path: []string{"/v0/groups/{group_id=*}/members/$ref"}, Method: []string{"POST"}, Body: "*", Handler: "rpc", }, &api.Endpoint{ Name: "GroupsService.RemoveMember", - Path: []string{"/v0/groups/{id=*}/members/{account_id}/$ref"}, + Path: []string{"/v0/groups/{group_id=*}/members/{account_id}/$ref"}, Method: []string{"DELETE"}, Body: "", Handler: "rpc", @@ -456,47 +458,49 @@ func RegisterGroupsServiceHandler(s server.Server, hdlr GroupsServiceHandler, op h := &groupsServiceHandler{hdlr} opts = append(opts, api.WithEndpoint(&api.Endpoint{ Name: "GroupsService.ListGroups", - Path: []string{"/v0/groups"}, - Method: []string{"GET"}, + Path: []string{"/api/v0/groups/groups-list"}, + Method: []string{"POST"}, + Body: "*", Handler: "rpc", })) opts = append(opts, api.WithEndpoint(&api.Endpoint{ Name: "GroupsService.GetGroup", - Path: []string{"/v0/groups/{id=*}"}, - Method: []string{"GET"}, + Path: []string{"/api/v0/groups/groups-get"}, + Method: []string{"POST"}, + Body: "*", Handler: "rpc", })) opts = append(opts, api.WithEndpoint(&api.Endpoint{ Name: "GroupsService.CreateGroup", - Path: []string{"/v0/groups"}, + Path: []string{"/api/v0/groups/groups-create"}, Method: []string{"POST"}, - Body: "group", + Body: "*", Handler: "rpc", })) opts = append(opts, api.WithEndpoint(&api.Endpoint{ Name: "GroupsService.UpdateGroup", - Path: []string{"/v0/groups/{group.id=*}"}, - Method: []string{"PATCH"}, - Body: "group", + Path: []string{"/api/v0/groups/groups-update"}, + Method: []string{"POST"}, + Body: "*", Handler: "rpc", })) opts = append(opts, api.WithEndpoint(&api.Endpoint{ Name: "GroupsService.DeleteGroup", - Path: []string{"/v0/groups/{id=*}"}, - Method: []string{"DELETE"}, - Body: "", + Path: []string{"/api/v0/groups/groups-delete"}, + Method: []string{"POST"}, + Body: "*", Handler: "rpc", })) opts = append(opts, api.WithEndpoint(&api.Endpoint{ Name: "GroupsService.AddMember", - Path: []string{"/v0/groups/{id=*}/members/$ref"}, + Path: []string{"/v0/groups/{group_id=*}/members/$ref"}, Method: []string{"POST"}, Body: "*", Handler: "rpc", })) opts = append(opts, api.WithEndpoint(&api.Endpoint{ Name: "GroupsService.RemoveMember", - Path: []string{"/v0/groups/{id=*}/members/{account_id}/$ref"}, + Path: []string{"/v0/groups/{group_id=*}/members/{account_id}/$ref"}, Method: []string{"DELETE"}, Body: "", Handler: "rpc", diff --git a/pkg/proto/v0/accounts.pb.web.go b/pkg/proto/v0/accounts.pb.web.go index f0fe5f7fe..528a82832 100644 --- a/pkg/proto/v0/accounts.pb.web.go +++ b/pkg/proto/v0/accounts.pb.web.go @@ -185,7 +185,7 @@ func (h *webGroupsServiceHandler) ListGroups(w http.ResponseWriter, r *http.Requ return } - render.Status(r, http.StatusOK) + render.Status(r, http.StatusCreated) render.JSON(w, r, resp) } @@ -209,7 +209,7 @@ func (h *webGroupsServiceHandler) GetGroup(w http.ResponseWriter, r *http.Reques return } - render.Status(r, http.StatusOK) + render.Status(r, http.StatusCreated) render.JSON(w, r, resp) } @@ -257,7 +257,7 @@ func (h *webGroupsServiceHandler) UpdateGroup(w http.ResponseWriter, r *http.Req return } - render.Status(r, http.StatusOK) + render.Status(r, http.StatusCreated) render.JSON(w, r, resp) } @@ -362,13 +362,13 @@ func RegisterGroupsServiceWeb(r chi.Router, i GroupsServiceHandler, middlewares h: i, } - r.MethodFunc("GET", "/v0/groups", handler.ListGroups) - r.MethodFunc("GET", "/v0/groups/{id=*}", handler.GetGroup) - r.MethodFunc("POST", "/v0/groups", handler.CreateGroup) - r.MethodFunc("PATCH", "/v0/groups/{group.id=*}", handler.UpdateGroup) - r.MethodFunc("DELETE", "/v0/groups/{id=*}", handler.DeleteGroup) - r.MethodFunc("POST", "/v0/groups/{id=*}/members/$ref", handler.AddMember) - r.MethodFunc("DELETE", "/v0/groups/{id=*}/members/{account_id}/$ref", handler.RemoveMember) + r.MethodFunc("POST", "/api/v0/groups/groups-list", handler.ListGroups) + r.MethodFunc("POST", "/api/v0/groups/groups-get", handler.GetGroup) + r.MethodFunc("POST", "/api/v0/groups/groups-create", handler.CreateGroup) + r.MethodFunc("POST", "/api/v0/groups/groups-update", handler.UpdateGroup) + r.MethodFunc("POST", "/api/v0/groups/groups-delete", handler.DeleteGroup) + r.MethodFunc("POST", "/v0/groups/{group_id=*}/members/$ref", handler.AddMember) + r.MethodFunc("DELETE", "/v0/groups/{group_id=*}/members/{account_id}/$ref", handler.RemoveMember) r.MethodFunc("GET", "/v0/groups/{id=*}/members/$ref", handler.ListMembers) } diff --git a/pkg/proto/v0/accounts.proto b/pkg/proto/v0/accounts.proto index eca6435b7..617757d9f 100644 --- a/pkg/proto/v0/accounts.proto +++ b/pkg/proto/v0/accounts.proto @@ -63,13 +63,15 @@ service GroupsService { rpc ListGroups(ListGroupsRequest) returns (ListGroupsResponse) { // List method maps to HTTP GET option (google.api.http) = { - get: "/v0/groups" + post: "/api/v0/groups/groups-list", + body: "*" }; } // Gets an groups rpc GetGroup(GetGroupRequest) returns (Group) { option (google.api.http) = { - get: "/v0/groups/{id=*}" + post: "/api/v0/groups/groups-get", + body: "*" }; } // Creates a group @@ -77,8 +79,8 @@ service GroupsService { // Create maps to HTTP POST. URL path as the collection name. // HTTP request body contains the resource option (google.api.http) = { - post: "/v0/groups" - body: "group" + post: "/api/v0/groups/groups-create" + body: "*" }; } // Updates a group @@ -86,8 +88,8 @@ service GroupsService { // Update maps to HTTP PATCH. Resource name is mapped to a URL path. // Resource is contained in the HTTP request body option (google.api.http) = { - patch: "/v0/groups/{group.id=*}" - body: "group" + post: "/api/v0/groups/groups-update" + body: "*" }; }; // Deletes a group @@ -95,7 +97,8 @@ service GroupsService { // Delete maps to HTTP DELETE. Resource name maps to the URL path. // There is no request body option (google.api.http) = { - delete: "/v0/groups/{id=*}" + post: "/api/v0/groups/groups-delete", + body: "*" }; } @@ -108,7 +111,7 @@ service GroupsService { rpc AddMember(AddMemberRequest) returns (Group) { // All request parameters go into body. option (google.api.http) = { - post: "/v0/groups/{id=*}/members/$ref" + post: "/v0/groups/{group_id=*}/members/$ref" body: "*" }; } @@ -116,7 +119,7 @@ service GroupsService { rpc RemoveMember(RemoveMemberRequest) returns (Group) { // All request parameters go into body. option (google.api.http) = { - delete: "/v0/groups/{id=*}/members/{account_id}/$ref" + delete: "/v0/groups/{group_id=*}/members/{account_id}/$ref" }; } // group:listmembers https://docs.microsoft.com/en-us/graph/api/group-list-members?view=graph-rest-1.0 @@ -471,14 +474,15 @@ message DeleteGroupRequest { } message AddMemberRequest { + // The id of the group to add a member to + string group_id = 1; // The account id to add - string id = 1; + string account_id = 2; } message RemoveMemberRequest { - // The group id - string id = 1; - + // The id of the group to remove a member from + string group_id = 1; // The account id to remove string account_id = 2; } @@ -514,7 +518,7 @@ message ListMembersRequest { // display names that include both "Test" and "String" string query = 4 [(google.api.field_behavior) = OPTIONAL]; - // The group id + // The id of the group to list members from string id = 5; } diff --git a/pkg/proto/v0/accounts.swagger.json b/pkg/proto/v0/accounts.swagger.json index 1e407c0f6..698065087 100644 --- a/pkg/proto/v0/accounts.swagger.json +++ b/pkg/proto/v0/accounts.swagger.json @@ -14,19 +14,13 @@ "/api/v0/accounts/accounts-create": { "post": { "summary": "Creates an account", - "operationId": "AccountsService_CreateAccount", + "operationId": "CreateAccount", "responses": { "200": { "description": "A successful response.", "schema": { "$ref": "#/definitions/settingsAccount" } - }, - "default": { - "description": "An unexpected error response", - "schema": { - "$ref": "#/definitions/runtimeError" - } } }, "parameters": [ @@ -47,19 +41,13 @@ "/api/v0/accounts/accounts-delete": { "post": { "summary": "Deletes an account", - "operationId": "AccountsService_DeleteAccount", + "operationId": "DeleteAccount", "responses": { "200": { "description": "A successful response.", "schema": { "properties": {} } - }, - "default": { - "description": "An unexpected error response", - "schema": { - "$ref": "#/definitions/runtimeError" - } } }, "parameters": [ @@ -80,19 +68,13 @@ "/api/v0/accounts/accounts-get": { "post": { "summary": "Gets an account", - "operationId": "AccountsService_GetAccount", + "operationId": "GetAccount", "responses": { "200": { "description": "A successful response.", "schema": { "$ref": "#/definitions/settingsAccount" } - }, - "default": { - "description": "An unexpected error response", - "schema": { - "$ref": "#/definitions/runtimeError" - } } }, "parameters": [ @@ -113,19 +95,13 @@ "/api/v0/accounts/accounts-list": { "post": { "summary": "Lists accounts", - "operationId": "AccountsService_ListAccounts", + "operationId": "ListAccounts", "responses": { "200": { "description": "A successful response.", "schema": { "$ref": "#/definitions/settingsListAccountsResponse" } - }, - "default": { - "description": "An unexpected error response", - "schema": { - "$ref": "#/definitions/runtimeError" - } } }, "parameters": [ @@ -146,19 +122,13 @@ "/api/v0/accounts/accounts-update": { "post": { "summary": "Updates an account", - "operationId": "AccountsService_UpdateAccount", + "operationId": "UpdateAccount", "responses": { "200": { "description": "A successful response.", "schema": { "$ref": "#/definitions/settingsAccount" } - }, - "default": { - "description": "An unexpected error response", - "schema": { - "$ref": "#/definitions/runtimeError" - } } }, "parameters": [ @@ -176,88 +146,25 @@ ] } }, - "/v0/groups": { - "get": { - "summary": "Lists groups", - "operationId": "GroupsService_ListGroups", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/settingsListGroupsResponse" - } - }, - "default": { - "description": "An unexpected error response", - "schema": { - "$ref": "#/definitions/runtimeError" - } - } - }, - "parameters": [ - { - "name": "page_size", - "description": "Optional. The maximum number of groups to return in the response.", - "in": "query", - "required": false, - "type": "integer", - "format": "int32" - }, - { - "name": "page_token", - "description": "Optional. A pagination token returned from a previous call to `Get`\nthat indicates from where search should continue.", - "in": "query", - "required": false, - "type": "string" - }, - { - "name": "field_mask.paths", - "description": "The set of field mask paths.", - "in": "query", - "required": false, - "type": "array", - "items": { - "type": "string" - }, - "collectionFormat": "multi" - }, - { - "name": "query", - "description": "Optional. Search criteria used to select the groups to return.\nIf no search criteria is specified then all groups will be\nreturned. TODO update query language\nQuery expressions can be used to restrict results based upon\nthe account properties where the operators `=`, `NOT`, `AND` and `OR`\ncan be used along with the suffix wildcard symbol `*`.\n\nThe string properties in a query expression should use escaped quotes\nfor values that include whitespace to prevent unexpected behavior.\n\nSome example queries are:\n\n* Query `display_name=Th*` returns accounts whose display_name\nstarts with \"Th\"\n* Query `display_name=\\\\\"Test String\\\\\"` returns groups with\ndisplay names that include both \"Test\" and \"String\"", - "in": "query", - "required": false, - "type": "string" - } - ], - "tags": [ - "GroupsService" - ] - }, + "/api/v0/groups/groups-create": { "post": { - "summary": "Creates a group", - "operationId": "GroupsService_CreateGroup", + "summary": "Creates an account", + "operationId": "CreateGroup", "responses": { "200": { "description": "A successful response.", "schema": { "$ref": "#/definitions/settingsGroup" } - }, - "default": { - "description": "An unexpected error response", - "schema": { - "$ref": "#/definitions/runtimeError" - } } }, "parameters": [ { "name": "body", - "description": "The account resource to create", "in": "body", "required": true, "schema": { - "$ref": "#/definitions/settingsGroup" + "$ref": "#/definitions/settingsCreateGroupRequest" } } ], @@ -266,100 +173,26 @@ ] } }, - "/v0/groups/{group.id}": { - "patch": { - "summary": "Updates a group", - "operationId": "GroupsService_UpdateGroup", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/settingsGroup" - } - }, - "default": { - "description": "An unexpected error response", - "schema": { - "$ref": "#/definitions/runtimeError" - } - } - }, - "parameters": [ - { - "name": "group.id", - "description": "The unique identifier for the group.\nReturned by default. Inherited from directoryObject. Key. Not nullable. Read-only.", - "in": "path", - "required": true, - "type": "string" - }, - { - "name": "body", - "description": "The group resource which replaces the resource on the server", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/settingsGroup" - } - } - ], - "tags": [ - "GroupsService" - ] - } - }, - "/v0/groups/{id}": { - "get": { - "summary": "Gets an groups", - "operationId": "GroupsService_GetGroup", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/settingsGroup" - } - }, - "default": { - "description": "An unexpected error response", - "schema": { - "$ref": "#/definitions/runtimeError" - } - } - }, - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "type": "string" - } - ], - "tags": [ - "GroupsService" - ] - }, - "delete": { - "summary": "Deletes a group", - "operationId": "GroupsService_DeleteGroup", + "/api/v0/groups/groups-delete": { + "post": { + "summary": "Deletes an account", + "operationId": "DeleteGroup", "responses": { "200": { "description": "A successful response.", "schema": { "properties": {} } - }, - "default": { - "description": "An unexpected error response", - "schema": { - "$ref": "#/definitions/runtimeError" - } } }, "parameters": [ { - "name": "id", - "in": "path", + "name": "body", + "in": "body", "required": true, - "type": "string" + "schema": { + "$ref": "#/definitions/settingsDeleteGroupRequest" + } } ], "tags": [ @@ -367,90 +200,103 @@ ] } }, - "/v0/groups/{id}/members/$ref": { - "get": { - "summary": "group:listmembers https://docs.microsoft.com/en-us/graph/api/group-list-members?view=graph-rest-1.0", - "operationId": "GroupsService_ListMembers", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/settingsListMembersResponse" - } - }, - "default": { - "description": "An unexpected error response", - "schema": { - "$ref": "#/definitions/runtimeError" - } - } - }, - "parameters": [ - { - "name": "id", - "description": "The group id", - "in": "path", - "required": true, - "type": "string" - }, - { - "name": "page_size", - "in": "query", - "required": false, - "type": "integer", - "format": "int32" - }, - { - "name": "page_token", - "description": "Optional. A pagination token returned from a previous call to `Get`\nthat indicates from where search should continue.", - "in": "query", - "required": false, - "type": "string" - }, - { - "name": "field_mask.paths", - "description": "The set of field mask paths.", - "in": "query", - "required": false, - "type": "array", - "items": { - "type": "string" - }, - "collectionFormat": "multi" - }, - { - "name": "query", - "description": "Optional. Search criteria used to select the groups to return.\nIf no search criteria is specified then all groups will be\nreturned. TODO update query language\nQuery expressions can be used to restrict results based upon\nthe account properties where the operators `=`, `NOT`, `AND` and `OR`\ncan be used along with the suffix wildcard symbol `*`.\n\nThe string properties in a query expression should use escaped quotes\nfor values that include whitespace to prevent unexpected behavior.\n\nSome example queries are:\n\n* Query `display_name=Th*` returns accounts whose display_name\nstarts with \"Th\"\n* Query `display_name=\\\\\"Test String\\\\\"` returns groups with\ndisplay names that include both \"Test\" and \"String\"", - "in": "query", - "required": false, - "type": "string" - } - ], - "tags": [ - "GroupsService" - ] - }, + "/api/v0/groups/groups-get": { "post": { - "summary": "group:addmember https://docs.microsoft.com/en-us/graph/api/group-post-members?view=graph-rest-1.0\u0026tabs=http", - "operationId": "GroupsService_AddMember", + "summary": "Gets an account", + "operationId": "GetGroup", "responses": { "200": { "description": "A successful response.", "schema": { "$ref": "#/definitions/settingsGroup" } - }, - "default": { - "description": "An unexpected error response", + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, "schema": { - "$ref": "#/definitions/runtimeError" + "$ref": "#/definitions/settingsGetGroupRequest" + } + } + ], + "tags": [ + "GroupsService" + ] + } + }, + "/api/v0/groups/groups-list": { + "post": { + "summary": "Lists accounts", + "operationId": "ListGroups", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/settingsListGroupsResponse" } } }, "parameters": [ { - "name": "id", - "description": "The account id to add", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/settingsListGroupsRequest" + } + } + ], + "tags": [ + "GroupsService" + ] + } + }, + "/api/v0/groups/groups-update": { + "post": { + "summary": "Updates an account", + "operationId": "UpdateGroup", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/settingsGroup" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/settingsUpdateGroupRequest" + } + } + ], + "tags": [ + "GroupsService" + ] + } + }, + "/v0/groups/{group_id}/members/$ref": { + "post": { + "summary": "group:addmember https://docs.microsoft.com/en-us/graph/api/group-post-members?view=graph-rest-1.0\u0026tabs=http", + "operationId": "AddMember", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/settingsGroup" + } + } + }, + "parameters": [ + { + "name": "group_id", + "description": "The id of the group to add a member to", "in": "path", "required": true, "type": "string" @@ -469,28 +315,22 @@ ] } }, - "/v0/groups/{id}/members/{account_id}/$ref": { + "/v0/groups/{group_id}/members/{account_id}/$ref": { "delete": { "summary": "group:removemember https://docs.microsoft.com/en-us/graph/api/group-delete-members?view=graph-rest-1.0", - "operationId": "GroupsService_RemoveMember", + "operationId": "RemoveMember", "responses": { "200": { "description": "A successful response.", "schema": { "$ref": "#/definitions/settingsGroup" } - }, - "default": { - "description": "An unexpected error response", - "schema": { - "$ref": "#/definitions/runtimeError" - } } }, "parameters": [ { - "name": "id", - "description": "The group id", + "name": "group_id", + "description": "The id of the group to remove a member from", "in": "path", "required": true, "type": "string" @@ -507,21 +347,67 @@ "GroupsService" ] } + }, + "/v0/groups/{id}/members/$ref": { + "get": { + "summary": "group:listmembers https://docs.microsoft.com/en-us/graph/api/group-list-members?view=graph-rest-1.0", + "operationId": "ListMembers", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/settingsListMembersResponse" + } + } + }, + "parameters": [ + { + "name": "id", + "description": "The id of the group to list members from", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "page_size", + "in": "query", + "required": false, + "type": "integer", + "format": "int32" + }, + { + "name": "page_token", + "description": "Optional. A pagination token returned from a previous call to `Get`\nthat indicates from where search should continue.", + "in": "query", + "required": false, + "type": "string" + }, + { + "name": "field_mask.paths", + "description": "The set of field mask paths.", + "in": "query", + "required": false, + "type": "array", + "items": { + "type": "string" + }, + "collectionFormat": "multi" + }, + { + "name": "query", + "description": "Optional. Search criteria used to select the groups to return.\nIf no search criteria is specified then all groups will be\nreturned. TODO update query language\nQuery expressions can be used to restrict results based upon\nthe account properties where the operators `=`, `NOT`, `AND` and `OR`\ncan be used along with the suffix wildcard symbol `*`.\n\nThe string properties in a query expression should use escaped quotes\nfor values that include whitespace to prevent unexpected behavior.\n\nSome example queries are:\n\n* Query `display_name=Th*` returns accounts whose display_name\nstarts with \"Th\"\n* Query `display_name=\\\\\"Test String\\\\\"` returns groups with\ndisplay names that include both \"Test\" and \"String\"", + "in": "query", + "required": false, + "type": "string" + } + ], + "tags": [ + "GroupsService" + ] + } } }, "definitions": { - "protobufAny": { - "type": "object", - "properties": { - "type_url": { - "type": "string" - }, - "value": { - "type": "string", - "format": "byte" - } - } - }, "protobufFieldMask": { "type": "object", "properties": { @@ -536,27 +422,6 @@ "description": "paths: \"f.a\"\n paths: \"f.b.d\"\n\nHere `f` represents a field in some root message, `a` and `b`\nfields in the message found in `f`, and `d` a field found in the\nmessage in `f.b`.\n\nField masks are used to specify a subset of fields that should be\nreturned by a get operation or modified by an update operation.\nField masks also have a custom JSON encoding (see below).\n\n# Field Masks in Projections\n\nWhen used in the context of a projection, a response message or\nsub-message is filtered by the API to only contain those fields as\nspecified in the mask. For example, if the mask in the previous\nexample is applied to a response message as follows:\n\n f {\n a : 22\n b {\n d : 1\n x : 2\n }\n y : 13\n }\n z: 8\n\nThe result will not contain specific values for fields x,y and z\n(their value will be set to the default, and omitted in proto text\noutput):\n\n\n f {\n a : 22\n b {\n d : 1\n }\n }\n\nA repeated field is not allowed except at the last position of a\npaths string.\n\nIf a FieldMask object is not present in a get operation, the\noperation applies to all fields (as if a FieldMask of all fields\nhad been specified).\n\nNote that a field mask does not necessarily apply to the\ntop-level response message. In case of a REST get operation, the\nfield mask applies directly to the response, but in case of a REST\nlist operation, the mask instead applies to each individual message\nin the returned resource list. In case of a REST custom method,\nother definitions may be used. Where the mask applies will be\nclearly documented together with its declaration in the API. In\nany case, the effect on the returned resource/resources is required\nbehavior for APIs.\n\n# Field Masks in Update Operations\n\nA field mask in update operations specifies which fields of the\ntargeted resource are going to be updated. The API is required\nto only change the values of the fields as specified in the mask\nand leave the others untouched. If a resource is passed in to\ndescribe the updated values, the API ignores the values of all\nfields not covered by the mask.\n\nIf a repeated field is specified for an update operation, new values will\nbe appended to the existing repeated field in the target resource. Note that\na repeated field is only allowed in the last position of a `paths` string.\n\nIf a sub-message is specified in the last position of the field mask for an\nupdate operation, then new value will be merged into the existing sub-message\nin the target resource.\n\nFor example, given the target message:\n\n f {\n b {\n d: 1\n x: 2\n }\n c: [1]\n }\n\nAnd an update message:\n\n f {\n b {\n d: 10\n }\n c: [2]\n }\n\nthen if the field mask is:\n\n paths: [\"f.b\", \"f.c\"]\n\nthen the result will be:\n\n f {\n b {\n d: 10\n x: 2\n }\n c: [1, 2]\n }\n\nAn implementation may provide options to override this default behavior for\nrepeated and message fields.\n\nIn order to reset a field's value to the default, the field must\nbe in the mask and set to the default value in the provided resource.\nHence, in order to reset all fields of a resource, provide a default\ninstance of the resource and set all fields in the mask, or do\nnot provide a mask as described below.\n\nIf a field mask is not present on update, the operation applies to\nall fields (as if a field mask of all fields has been specified).\nNote that in the presence of schema evolution, this may mean that\nfields the client does not know and has therefore not filled into\nthe request will be reset to their default. If this is unwanted\nbehavior, a specific service may require a client to always specify\na field mask, producing an error if not.\n\nAs with get operations, the location of the resource which\ndescribes the updated values in the request message depends on the\noperation kind. In any case, the effect of the field mask is\nrequired to be honored by the API.\n\n## Considerations for HTTP REST\n\nThe HTTP kind of an update operation which uses a field mask must\nbe set to PATCH instead of PUT in order to satisfy HTTP semantics\n(PUT must only be used for full updates).\n\n# JSON Encoding of Field Masks\n\nIn JSON, a field mask is encoded as a single string where paths are\nseparated by a comma. Fields name in each path are converted\nto/from lower-camel naming conventions.\n\nAs an example, consider the following message declarations:\n\n message Profile {\n User user = 1;\n Photo photo = 2;\n }\n message User {\n string display_name = 1;\n string address = 2;\n }\n\nIn proto a field mask for `Profile` may look as such:\n\n mask {\n paths: \"user.display_name\"\n paths: \"photo\"\n }\n\nIn JSON, the same mask is represented as below:\n\n {\n mask: \"user.displayName,photo\"\n }\n\n# Field Masks and Oneof Fields\n\nField masks treat fields in oneofs just as regular fields. Consider the\nfollowing message:\n\n message SampleMessage {\n oneof test_oneof {\n string name = 4;\n SubMessage sub_message = 9;\n }\n }\n\nThe field mask can be:\n\n mask {\n paths: \"name\"\n }\n\nOr:\n\n mask {\n paths: \"sub_message\"\n }\n\nNote that oneof type names (\"test_oneof\" in this case) cannot be used in\npaths.\n\n## Field Mask Verification\n\nThe implementation of any API method which has a FieldMask type field in the\nrequest should verify the included field paths, and return an\n`INVALID_ARGUMENT` error if any path is unmappable.", "title": "`FieldMask` represents a set of symbolic field paths, for example:" }, - "runtimeError": { - "type": "object", - "properties": { - "error": { - "type": "string" - }, - "code": { - "type": "integer", - "format": "int32" - }, - "message": { - "type": "string" - }, - "details": { - "type": "array", - "items": { - "$ref": "#/definitions/protobufAny" - } - } - } - }, "settingsAccount": { "type": "object", "properties": { @@ -698,7 +563,11 @@ "settingsAddMemberRequest": { "type": "object", "properties": { - "id": { + "group_id": { + "type": "string", + "title": "The id of the group to add a member to" + }, + "account_id": { "type": "string", "title": "The account id to add" } @@ -713,6 +582,15 @@ } } }, + "settingsCreateGroupRequest": { + "type": "object", + "properties": { + "group": { + "$ref": "#/definitions/settingsGroup", + "title": "The account resource to create" + } + } + }, "settingsDeleteAccountRequest": { "type": "object", "properties": { @@ -721,6 +599,14 @@ } } }, + "settingsDeleteGroupRequest": { + "type": "object", + "properties": { + "id": { + "type": "string" + } + } + }, "settingsGetAccountRequest": { "type": "object", "properties": { @@ -729,6 +615,14 @@ } } }, + "settingsGetGroupRequest": { + "type": "object", + "properties": { + "id": { + "type": "string" + } + } + }, "settingsGroup": { "type": "object", "properties": { @@ -886,6 +780,29 @@ } } }, + "settingsListGroupsRequest": { + "type": "object", + "properties": { + "page_size": { + "type": "integer", + "format": "int32", + "title": "Optional. The maximum number of groups to return in the response" + }, + "page_token": { + "type": "string", + "title": "Optional. A pagination token returned from a previous call to `Get`\nthat indicates from where search should continue" + }, + "field_mask": { + "$ref": "#/definitions/protobufFieldMask", + "description": "Optional. Used to specify a subset of fields that should be\nreturned by a get operation or modified by an update operation." + }, + "query": { + "type": "string", + "description": "TODO update query language\nQuery expressions can be used to restrict results based upon\nthe account properties where the operators `=`, `NOT`, `AND` and `OR`\ncan be used along with the suffix wildcard symbol `*`.\n\nThe string properties in a query expression should use escaped quotes\nfor values that include whitespace to prevent unexpected behavior.\n\nSome example queries are:\n\n* Query `display_name=Th*` returns accounts whose display_name\nstarts with \"Th\"\n* Query `display_name=\\\\\"Test String\\\\\"` returns groups with\ndisplay names that include both \"Test\" and \"String\"", + "title": "Optional. Search criteria used to select the groups to return.\nIf no search criteria is specified then all groups will be\nreturned" + } + } + }, "settingsListGroupsResponse": { "type": "object", "properties": { @@ -983,6 +900,19 @@ "title": "The update mask applies to the resource. For the `FieldMask` definition,\nsee https://developers.google.com/protocol-buffers/docs/reference/google.protobuf#fieldmask" } } + }, + "settingsUpdateGroupRequest": { + "type": "object", + "properties": { + "group": { + "$ref": "#/definitions/settingsGroup", + "title": "The group resource which replaces the resource on the server" + }, + "update_mask": { + "$ref": "#/definitions/protobufFieldMask", + "title": "The update mask applies to the resource. For the `FieldMask` definition,\nsee https://developers.google.com/protocol-buffers/docs/reference/google.protobuf#fieldmask" + } + } } } } diff --git a/pkg/server/grpc/server.go b/pkg/server/grpc/server.go index 675286286..823861415 100644 --- a/pkg/server/grpc/server.go +++ b/pkg/server/grpc/server.go @@ -28,6 +28,9 @@ func Server(opts ...Option) grpc.Service { if err = proto.RegisterAccountsServiceHandler(service.Server(), hdlr); err != nil { options.Logger.Fatal().Err(err).Msg("could not register service handler") } + if err = proto.RegisterGroupsServiceHandler(service.Server(), hdlr); err != nil { + options.Logger.Fatal().Err(err).Msg("could not register groups handler") + } service.Init() return service diff --git a/pkg/service/v0/accounts.go b/pkg/service/v0/accounts.go new file mode 100644 index 000000000..9433d71ea --- /dev/null +++ b/pkg/service/v0/accounts.go @@ -0,0 +1,401 @@ +package service + +import ( + "context" + "encoding/json" + "fmt" + "io/ioutil" + "os" + "path/filepath" + "regexp" + "time" + + "github.com/CiscoM31/godata" + "github.com/blevesearch/bleve" + "github.com/blevesearch/bleve/search/query" + "github.com/gofrs/uuid" + "github.com/golang/protobuf/ptypes/empty" + merrors "github.com/micro/go-micro/v2/errors" + "github.com/owncloud/ocis-accounts/pkg/proto/v0" + "github.com/owncloud/ocis-accounts/pkg/provider" + "github.com/tredoe/osutil/user/crypt" + "google.golang.org/protobuf/types/known/timestamppb" + + // register crypt functions + _ "github.com/tredoe/osutil/user/crypt/apr1_crypt" + _ "github.com/tredoe/osutil/user/crypt/md5_crypt" + _ "github.com/tredoe/osutil/user/crypt/sha256_crypt" + _ "github.com/tredoe/osutil/user/crypt/sha512_crypt" +) + +func (s Service) indexAccounts(path string) (err error) { + + var f *os.File + if f, err = os.Open(path); err != nil { + s.log.Error().Err(err).Str("dir", path).Msg("could not open accounts folder") + return + } + list, err := f.Readdir(-1) + f.Close() + if err != nil { + s.log.Error().Err(err).Str("dir", path).Msg("could not list accounts folder") + return + } + for _, file := range list { + a := &proto.Account{} + if err = s.loadAccount(file.Name(), a); err != nil { + s.log.Error().Err(err).Str("account", file.Name()).Msg("could not load account") + continue + } + s.log.Debug().Interface("account", a).Msg("found account") + if err = s.index.Index(a.Id, a); err != nil { + s.log.Error().Err(err).Interface("account", a).Msg("could not index account") + continue + } + } + + return +} + +// an auth request is currently hardcoded and has to match this regex +// login eq \"teddy\" and password eq \"F&1!b90t111!\" +var authQuery = regexp.MustCompile(`^login eq '(.*)' and password eq '(.*)'$`) // TODO how is ' escaped in the password? + +func (s Service) loadAccount(id string, a *proto.Account) (err error) { + path := filepath.Join(s.Config.Server.AccountsDataPath, "accounts", id) + + var data []byte + if data, err = ioutil.ReadFile(path); err != nil { + return merrors.NotFound(s.id, "could not read account: %v", err.Error()) + } + + if err = json.Unmarshal(data, a); err != nil { + return merrors.InternalServerError(s.id, "could not unmarshal account: %v", err.Error()) + } + return +} + +// loggableAccount redacts the password from the account +func loggableAccount(a *proto.Account) *proto.Account { + if a != nil && a.PasswordProfile != nil { + a.PasswordProfile.Password = "***REMOVED***" + } + return a +} + +func (s Service) writeAccount(a *proto.Account) (err error) { + + // leave only the group id + s.inflateMemberOf(a) + + var bytes []byte + if bytes, err = json.Marshal(a); err != nil { + return merrors.InternalServerError(s.id, "could not marshal account: %v", err.Error()) + } + + path := filepath.Join(s.Config.Server.AccountsDataPath, "accounts", a.Id) + if err = ioutil.WriteFile(path, bytes, 0600); err != nil { + return merrors.InternalServerError(s.id, "could not write account: %v", err.Error()) + } + return +} + +func (s Service) expandMemberOf(a *proto.Account) { + if a == nil { + return + } + expanded := []*proto.Group{} + for i := range a.MemberOf { + g := &proto.Group{} + // TODO resolve by name, when a create or update is issued they may not have an id? fall back to searching the group id in the index? + if err := s.loadGroup(a.MemberOf[i].Id, g); err == nil { + g.Members = nil // always hide members when expanding + expanded = append(expanded, g) + } else { + // log errors but continue execution for now + s.log.Error().Err(err).Str("id", a.MemberOf[i].Id).Msg("could not load group") + } + } + a.MemberOf = expanded +} + +// inflateGroups replaces the groups of a user with an instance that only contains the id +func (s Service) inflateMemberOf(a *proto.Account) { + if a == nil { + return + } + inflated := []*proto.Group{} + for i := range a.MemberOf { + if a.MemberOf[i].Id != "" { + inflated = append(inflated, &proto.Group{Id: a.MemberOf[i].Id}) + } else { + // TODO fetch and use an id when group only has a name but no id + s.log.Error().Str("id", a.Id).Interface("group", a.MemberOf[i]).Msg("resolving groups by name is not implemented yet") + } + } + a.MemberOf = inflated +} + +func (s Service) passwordIsValid(hash string, pwd string) (ok bool) { + defer func() { + if r := recover(); r != nil { + s.log.Error().Err(fmt.Errorf("%s", r)).Str("hash", hash).Msg("password lib panicked") + } + }() + + c := crypt.NewFromHash(hash) + return c.Verify(hash, []byte(pwd)) == nil +} + +// ListAccounts implements the AccountsServiceHandler interface +// the query contains account properties +func (s Service) ListAccounts(ctx context.Context, in *proto.ListAccountsRequest, out *proto.ListAccountsResponse) (err error) { + + var password string + + var query query.Query + + // check if this looks like an auth request + match := authQuery.FindStringSubmatch(in.Query) + if len(match) == 3 { + in.Query = fmt.Sprintf("preferred_name eq '%s'", match[1]) // todo fetch email? make query configurable + password = match[2] + if password == "" { + return merrors.Unauthorized(s.id, "password must not be empty") + } + } + + if in.Query != "" { + // parse the query like an odata filter + var q *godata.GoDataFilterQuery + if q, err = godata.ParseFilterString(in.Query); err != nil { + s.log.Error().Err(err).Msg("could not parse query") + return merrors.InternalServerError(s.id, "could not parse query: %v", err.Error()) + } + + // convert to bleve query + query, err = provider.BuildBleveQuery(q) + if err != nil { + s.log.Error().Err(err).Msg("could not build bleve query") + return merrors.InternalServerError(s.id, "could not build bleve query: %v", err.Error()) + } + } else { + query = bleve.NewMatchAllQuery() + } + + s.log.Debug().Interface("query", query).Msg("using query") + + searchRequest := bleve.NewSearchRequest(query) + var searchResult *bleve.SearchResult + searchResult, err = s.index.Search(searchRequest) + if err != nil { + s.log.Error().Err(err).Msg("could not execute bleve search") + return merrors.InternalServerError(s.id, "could not execute bleve search: %v", err.Error()) + } + + s.log.Debug().Interface("result", searchResult).Msg("result") + + out.Accounts = make([]*proto.Account, 0) + + for _, hit := range searchResult.Hits { + + a := &proto.Account{} + if err = s.loadAccount(hit.ID, a); err != nil { + s.log.Error().Err(err).Str("account", hit.ID).Msg("could not load account, skipping") + continue + } + var currentHash string + if a.PasswordProfile != nil { + currentHash = a.PasswordProfile.Password + } + s.log.Debug().Interface("account", loggableAccount(a)).Msg("found account") + + if password != "" { + if a.PasswordProfile == nil { + s.log.Debug().Interface("account", loggableAccount(a)).Msg("no password profile") + return merrors.Unauthorized(s.id, "invalid password") + } + if !s.passwordIsValid(currentHash, password) { + return merrors.Unauthorized(s.id, "invalid password") + } + } + // TODO add groups if requested + // if in.FieldMask ... + s.expandMemberOf(a) + + // remove password before returning + a.PasswordProfile.Password = "" + + out.Accounts = append(out.Accounts, a) + } + + return +} + +// GetAccount implements the AccountsServiceHandler interface +func (s Service) GetAccount(c context.Context, in *proto.GetAccountRequest, out *proto.Account) (err error) { + var id string + if id, err = cleanupID(in.Id); err != nil { + return merrors.InternalServerError(s.id, "could not clean up account id: %v", err.Error()) + } + + if err = s.loadAccount(id, out); err != nil { + s.log.Error().Err(err).Str("id", id).Msg("could not load account") + return + } + s.log.Debug().Interface("account", loggableAccount(out)).Msg("found account") + + // TODO add groups if requested + // if in.FieldMask ... + s.expandMemberOf(out) + + // remove password + out.PasswordProfile.Password = "" + + return +} + +// CreateAccount implements the AccountsServiceHandler interface +func (s Service) CreateAccount(c context.Context, in *proto.CreateAccountRequest, out *proto.Account) (err error) { + var id string + if in.Account == nil { + return merrors.BadRequest(s.id, "account missing") + } + if in.Account.Id == "" { + in.Account.Id = uuid.Must(uuid.NewV4()).String() + } + + if id, err = cleanupID(in.Account.Id); err != nil { + return merrors.InternalServerError(s.id, "could not clean up account id: %v", err.Error()) + } + path := filepath.Join(s.Config.Server.AccountsDataPath, "accounts", id) + + if in.Account.PasswordProfile != nil && in.Account.PasswordProfile.Password != "" { + // encrypt password + c := crypt.New(crypt.SHA512) + if in.Account.PasswordProfile.Password, err = c.Generate([]byte(in.Account.PasswordProfile.Password), nil); err != nil { + s.log.Error().Err(err).Str("id", id).Interface("account", loggableAccount(in.Account)).Msg("could not hash password") + return merrors.InternalServerError(s.id, "could not hash password: %v", err.Error()) + } + } + + // extract group id + // TODO groups should be ignored during create, use groups.AddMember? return error? + if err = s.writeAccount(in.Account); err != nil { + s.log.Error().Err(err).Interface("account", loggableAccount(in.Account)).Msg("could not persist new account") + return + } + + if err = s.index.Index(id, in.Account); err != nil { + s.log.Error().Err(err).Str("id", id).Str("path", path).Interface("account", loggableAccount(in.Account)).Msg("could not index new account") + return merrors.InternalServerError(s.id, "could not index new account: %v", err.Error()) + } + + return +} + +// UpdateAccount implements the AccountsServiceHandler interface +// read only fields are ignored +// TODO how can we unset specific values? using the update mask +func (s Service) UpdateAccount(c context.Context, in *proto.UpdateAccountRequest, out *proto.Account) (err error) { + var id string + if in.Account == nil { + return merrors.BadRequest(s.id, "account missing") + } + if in.Account.Id == "" { + return merrors.BadRequest(s.id, "account id missing") + } + + if id, err = cleanupID(in.Account.Id); err != nil { + return merrors.InternalServerError(s.id, "could not clean up account id: %v", err.Error()) + } + path := filepath.Join(s.Config.Server.AccountsDataPath, "accounts", id) + + if err = s.loadAccount(id, out); err != nil { + s.log.Error().Err(err).Str("id", id).Msg("could not load account") + return + } + s.log.Debug().Interface("account", loggableAccount(out)).Msg("found account") + + t := time.Now() + tsnow := ×tamppb.Timestamp{ + Seconds: t.Unix(), + Nanos: int32(t.Nanosecond()), + } + + // id read-only + out.AccountEnabled = in.Account.AccountEnabled + out.IsResourceAccount = in.Account.IsResourceAccount + // creation-type read only + out.Identities = in.Account.Identities + out.DisplayName = in.Account.DisplayName + out.PreferredName = in.Account.PreferredName + out.UidNumber = in.Account.UidNumber + out.GidNumber = in.Account.GidNumber + out.Mail = in.Account.Mail // read only? + out.Description = in.Account.Description + + if in.Account.PasswordProfile != nil && in.Account.PasswordProfile.Password != "" { + // encrypt password + c := crypt.New(crypt.SHA512) + if out.PasswordProfile.Password, err = c.Generate([]byte(in.Account.PasswordProfile.Password), nil); err != nil { + s.log.Error().Err(err).Str("id", id).Interface("account", loggableAccount(in.Account)).Msg("could not hash password") + return merrors.InternalServerError(s.id, "could not hash password: %v", err.Error()) + } + out.PasswordProfile.LastPasswordChangeDateTime = tsnow + } + // lastPasswordChangeDateTime calculated, see password + out.PasswordProfile.PasswordPolicies = in.Account.PasswordProfile.PasswordPolicies + out.PasswordProfile.ForceChangePasswordNextSignIn = in.Account.PasswordProfile.ForceChangePasswordNextSignIn + out.PasswordProfile.ForceChangePasswordNextSignInWithMfa = in.Account.PasswordProfile.ForceChangePasswordNextSignInWithMfa + + // memberOf read only + // createdDateTime read only + // deleteDateTime read only + + out.OnPremisesSyncEnabled = in.Account.OnPremisesSyncEnabled + // ... TODO on prem for sync + + if out.ExternalUserState != in.Account.ExternalUserState { + out.ExternalUserState = in.Account.ExternalUserState + out.ExternalUserStateChangeDateTime = tsnow + } + // out.RefreshTokensValidFromDateTime TODO use to invalidate all existing sessions + // out.SignInSessionsValidFromDateTime TODO use to invalidate all existing sessions + + if err = s.writeAccount(out); err != nil { + s.log.Error().Err(err).Interface("account", loggableAccount(out)).Msg("could not persist updated account") + return + } + + if err = s.index.Index(id, out); err != nil { + s.log.Error().Err(err).Str("id", id).Str("path", path).Interface("account", loggableAccount(out)).Msg("could not index new account") + return merrors.InternalServerError(s.id, "could not index updated account: %v", err.Error()) + } + + // remove password + out.PasswordProfile.Password = "" + + return +} + +// DeleteAccount implements the AccountsServiceHandler interface +func (s Service) DeleteAccount(c context.Context, in *proto.DeleteAccountRequest, out *empty.Empty) (err error) { + var id string + if id, err = cleanupID(in.Id); err != nil { + return merrors.InternalServerError(s.id, "could not clean up account id: %v", err.Error()) + } + path := filepath.Join(s.Config.Server.AccountsDataPath, "accounts", id) + + if err = os.Remove(path); err != nil { + s.log.Error().Err(err).Str("id", id).Str("path", path).Msg("could not remove account") + return merrors.InternalServerError(s.id, "could not remove account: %v", err.Error()) + } + + if err = s.index.Delete(id); err != nil { + s.log.Error().Err(err).Str("id", id).Str("path", path).Msg("could not remove account from index") + return merrors.InternalServerError(s.id, "could not remove account from index: %v", err.Error()) + } + // TODO delete member relationship in groups + return +} diff --git a/pkg/service/v0/groups.go b/pkg/service/v0/groups.go new file mode 100644 index 000000000..8fe4d0ecd --- /dev/null +++ b/pkg/service/v0/groups.go @@ -0,0 +1,321 @@ +package service + +import ( + "context" + "encoding/json" + "errors" + "io/ioutil" + "os" + "path/filepath" + + "github.com/CiscoM31/godata" + "github.com/blevesearch/bleve" + "github.com/blevesearch/bleve/search/query" + "github.com/gofrs/uuid" + "github.com/golang/protobuf/ptypes/empty" + merrors "github.com/micro/go-micro/v2/errors" + "github.com/owncloud/ocis-accounts/pkg/proto/v0" + "github.com/owncloud/ocis-accounts/pkg/provider" +) + +func (s Service) indexGroups(path string) (err error) { + var f *os.File + if f, err = os.Open(path); err != nil { + s.log.Error().Err(err).Str("dir", path).Msg("could not open groups folder") + return + } + list, err := f.Readdir(-1) + f.Close() + if err != nil { + s.log.Error().Err(err).Str("dir", path).Msg("could not list groups folder") + return + } + for _, file := range list { + g := &proto.Group{} + if err = s.loadGroup(file.Name(), g); err != nil { + s.log.Error().Err(err).Str("group", file.Name()).Msg("could not load group") + continue + } + s.log.Debug().Interface("group", g).Msg("found group") + if err = s.index.Index(g.Id, g); err != nil { + s.log.Error().Err(err).Interface("group", g).Msg("could not index group") + continue + } + } + + return +} + +func (s Service) loadGroup(id string, g *proto.Group) (err error) { + path := filepath.Join(s.Config.Server.AccountsDataPath, "groups", id) + + var data []byte + if data, err = ioutil.ReadFile(path); err != nil { + return merrors.NotFound(s.id, "could not read group: %v", err.Error()) + } + + if err = json.Unmarshal(data, g); err != nil { + return merrors.InternalServerError(s.id, "could not unmarshal group: %v", err.Error()) + } + + return +} + +func (s Service) writeGroup(g *proto.Group) (err error) { + + // leave only the member id + s.inflateMembers(g) + + var bytes []byte + if bytes, err = json.Marshal(g); err != nil { + return merrors.InternalServerError(s.id, "could not marshal group: %v", err.Error()) + } + + path := filepath.Join(s.Config.Server.AccountsDataPath, "groups", g.Id) + if err = ioutil.WriteFile(path, bytes, 0600); err != nil { + return merrors.InternalServerError(s.id, "could not write group: %v", err.Error()) + } + return +} + +func (s Service) expandMembers(g *proto.Group) { + if g == nil { + return + } + expanded := []*proto.Account{} + for i := range g.Members { + // TODO resolve by name, when a create or update is issued they may not have an id? fall back to searching the group id in the index? + a := &proto.Account{} + if err := s.loadAccount(g.Members[i].Id, a); err == nil { + expanded = append(expanded, a) + } else { + // log errors but continue execution for now + s.log.Error().Err(err).Str("id", g.Members[i].Id).Msg("could not load account") + } + } + g.Members = expanded +} + +// inflateGroups replaces the groups of a user with an instance that only contains the id +func (s Service) inflateMembers(g *proto.Group) { + if g == nil { + return + } + inflated := []*proto.Account{} + for i := range g.Members { + if g.Members[i].Id != "" { + inflated = append(inflated, &proto.Account{Id: g.Members[i].Id}) + } else { + // TODO fetch and use an id when group only has a name but no id + s.log.Error().Str("id", g.Id).Interface("account", g.Members[i]).Msg("resolving members by name is not implemented yet") + } + } + g.Members = inflated +} + +// ListGroups implements the GroupsServiceHandler interface +func (s Service) ListGroups(c context.Context, in *proto.ListGroupsRequest, out *proto.ListGroupsResponse) (err error) { + + var query query.Query + + if in.Query != "" { + // parse the query like an odata filter + var q *godata.GoDataFilterQuery + if q, err = godata.ParseFilterString(in.Query); err != nil { + s.log.Error().Err(err).Msg("could not parse query") + return merrors.InternalServerError(s.id, "could not parse query: %v", err.Error()) + } + + // convert to bleve query + query, err = provider.BuildBleveQuery(q) + if err != nil { + s.log.Error().Err(err).Msg("could not build bleve query") + return merrors.InternalServerError(s.id, "could not build bleve query: %v", err.Error()) + } + } else { + query = bleve.NewMatchAllQuery() + } + + s.log.Debug().Interface("query", query).Msg("using query") + + searchRequest := bleve.NewSearchRequest(query) + var searchResult *bleve.SearchResult + searchResult, err = s.index.Search(searchRequest) + if err != nil { + s.log.Error().Err(err).Msg("could not execute bleve search") + return merrors.InternalServerError(s.id, "could not execute bleve search: %v", err.Error()) + } + + s.log.Debug().Interface("result", searchResult).Msg("result") + + out.Groups = make([]*proto.Group, 0) + + for _, hit := range searchResult.Hits { + + g := &proto.Group{} + if err = s.loadGroup(hit.ID, g); err != nil { + s.log.Error().Err(err).Str("group", hit.ID).Msg("could not load group, skipping") + continue + } + s.log.Debug().Interface("group", g).Msg("found group") + + // TODO add accounts if requested + // if in.FieldMask ... + s.expandMembers(g) + + out.Groups = append(out.Groups, g) + } + + return +} + +// GetGroup implements the GroupsServiceHandler interface +func (s Service) GetGroup(c context.Context, in *proto.GetGroupRequest, out *proto.Group) (err error) { + var id string + if id, err = cleanupID(in.Id); err != nil { + return merrors.InternalServerError(s.id, "could not clean up group id: %v", err.Error()) + } + + if err = s.loadGroup(id, out); err != nil { + s.log.Error().Err(err).Str("id", id).Msg("could not load group") + return + } + s.log.Debug().Interface("group", out).Msg("found group") + + // TODO only add accounts if requested + // if in.FieldMask ... + s.expandMembers(out) + + return +} + +// CreateGroup implements the GroupsServiceHandler interface +func (s Service) CreateGroup(c context.Context, in *proto.CreateGroupRequest, out *proto.Group) (err error) { + var id string + if in.Group == nil { + return merrors.BadRequest(s.id, "account missing") + } + if in.Group.Id == "" { + in.Group.Id = uuid.Must(uuid.NewV4()).String() + } + + if id, err = cleanupID(in.Group.Id); err != nil { + return merrors.InternalServerError(s.id, "could not clean up account id: %v", err.Error()) + } + path := filepath.Join(s.Config.Server.AccountsDataPath, "groups", id) + + // extract member id + s.inflateMembers(in.Group) + + if err = s.writeGroup(in.Group); err != nil { + s.log.Error().Err(err).Interface("group", in.Group).Msg("could not persist new group") + return + } + + if err = s.index.Index(id, in.Group); err != nil { + s.log.Error().Err(err).Str("id", id).Str("path", path).Interface("group", in.Group).Msg("could not index new group") + return merrors.InternalServerError(s.id, "could not index new group: %v", err.Error()) + } + + return +} + +// UpdateGroup implements the GroupsServiceHandler interface +func (s Service) UpdateGroup(c context.Context, in *proto.UpdateGroupRequest, out *proto.Group) (err error) { + return merrors.InternalServerError(s.id, "not implemented") +} + +// DeleteGroup implements the GroupsServiceHandler interface +func (s Service) DeleteGroup(c context.Context, in *proto.DeleteGroupRequest, out *empty.Empty) (err error) { + var id string + if id, err = cleanupID(in.Id); err != nil { + return merrors.InternalServerError(s.id, "could not clean up group id: %v", err.Error()) + } + path := filepath.Join(s.Config.Server.AccountsDataPath, "groups", id) + + if err = os.Remove(path); err != nil { + s.log.Error().Err(err).Str("id", id).Str("path", path).Msg("could not remove group") + return merrors.InternalServerError(s.id, "could not remove group: %v", err.Error()) + } + + if err = s.index.Delete(id); err != nil { + s.log.Error().Err(err).Str("id", id).Str("path", path).Msg("could not remove group from index") + return merrors.InternalServerError(s.id, "could not remove group from index: %v", err.Error()) + } + + // TODO delete memberof relationship in users + return +} + +// AddMember implements the GroupsServiceHandler interface +func (s Service) AddMember(c context.Context, in *proto.AddMemberRequest, out *proto.Group) (err error) { + + // cleanup ids + var groupID string + if groupID, err = cleanupID(in.GroupId); err != nil { + return merrors.InternalServerError(s.id, "could not clean up group id: %v", err.Error()) + } + + var accountID string + if accountID, err = cleanupID(in.AccountId); err != nil { + return merrors.InternalServerError(s.id, "could not clean up account id: %v", err.Error()) + } + + // load structs + a := &proto.Account{} + if err = s.loadAccount(accountID, a); err != nil { + s.log.Error().Err(err).Str("id", accountID).Msg("could not load account") + return + } + + g := &proto.Group{} + if err = s.loadGroup(groupID, g); err != nil { + s.log.Error().Err(err).Str("id", groupID).Msg("could not load group") + return + } + + // check if we need to add the account to the group + alreadyRelated := false + for i := range g.Members { + if g.Members[i].Id == a.Id { + alreadyRelated = true + } + } + if alreadyRelated == false { + g.Members = append(g.Members, a) + } + + // check if we need to add the group to the account + alreadyRelated = false + for i := range a.MemberOf { + if a.MemberOf[i].Id == g.Id { + alreadyRelated = true + } + } + if alreadyRelated == false { + a.MemberOf = append(a.MemberOf, g) + } + + if err = s.writeAccount(a); err != nil { + s.log.Error().Err(err).Interface("account", a).Msg("could not persist account") + return + } + if err = s.writeGroup(g); err != nil { + s.log.Error().Err(err).Interface("group", g).Msg("could not persist group") + return + } + // TODO rollback changes when only one of them failed? + // TODO store relation in another file? + // TODO return error if they are already related? + return nil +} + +// RemoveMember implements the GroupsServiceHandler interface +func (s Service) RemoveMember(c context.Context, in *proto.RemoveMemberRequest, out *proto.Group) error { + return errors.New("not implemented") +} + +// ListMembers implements the GroupsServiceHandler interface +func (s Service) ListMembers(c context.Context, in *proto.ListMembersRequest, out *proto.ListMembersResponse) error { + return errors.New("not implemented") +} diff --git a/pkg/service/v0/service.go b/pkg/service/v0/service.go index d00384681..22ad3a03f 100644 --- a/pkg/service/v0/service.go +++ b/pkg/service/v0/service.go @@ -1,36 +1,19 @@ package service import ( - "context" "encoding/json" "errors" "fmt" "io/ioutil" "os" "path/filepath" - "regexp" "strings" - "github.com/CiscoM31/godata" "github.com/blevesearch/bleve" "github.com/blevesearch/bleve/analysis/analyzer/keyword" - "github.com/blevesearch/bleve/search/query" - "github.com/gofrs/uuid" - "github.com/golang/protobuf/ptypes/empty" - mclient "github.com/micro/go-micro/v2/client" "github.com/owncloud/ocis-accounts/pkg/config" "github.com/owncloud/ocis-accounts/pkg/proto/v0" - "github.com/owncloud/ocis-accounts/pkg/provider" "github.com/owncloud/ocis-pkg/v2/log" - settings "github.com/owncloud/ocis-settings/pkg/proto/v0" - "github.com/tredoe/osutil/user/crypt" - - merrors "github.com/micro/go-micro/v2/errors" - // register crypt functions - _ "github.com/tredoe/osutil/user/crypt/apr1_crypt" - _ "github.com/tredoe/osutil/user/crypt/md5_crypt" - _ "github.com/tredoe/osutil/user/crypt/sha256_crypt" - _ "github.com/tredoe/osutil/user/crypt/sha512_crypt" ) // New returns a new instance of Service @@ -138,47 +121,33 @@ func New(opts ...Option) (s *Service, err error) { return nil, fmt.Errorf("%s is not a directory", accountsDir) } + if err = os.MkdirAll(filepath.Join(cfg.Server.AccountsDataPath, "groups"), 0700); err != nil { + return nil, err + } + mapping := bleve.NewIndexMapping() // keep all symbols in terms to allow exact maching, eg. emails mapping.DefaultAnalyzer = keyword.Name // TODO don't bother to store fields as we will load the account from disk + //groupsFieldMapping := bleve.NewTextFieldMapping() + //blogMapping.AddFieldMappingsAt("memberOf", nameFieldMapping) + // TODO index groups and accounts as different types? s = &Service{ id: cfg.GRPC.Namespace + "." + cfg.Server.Name, + log: logger, Config: cfg, } if s.index, err = bleve.New(filepath.Join(cfg.Server.AccountsDataPath, "index.bleve"), mapping); err != nil { return } - var f *os.File - if f, err = os.Open(filepath.Join(cfg.Server.AccountsDataPath, "accounts")); err != nil { - logger.Error().Err(err).Str("dir", filepath.Join(cfg.Server.AccountsDataPath, "accounts")).Msg("could not open accounts folder") - return + + if err = s.indexAccounts(filepath.Join(cfg.Server.AccountsDataPath, "accounts")); err != nil { + return nil, err } - list, err := f.Readdir(-1) - f.Close() - if err != nil { - logger.Error().Err(err).Str("dir", filepath.Join(cfg.Server.AccountsDataPath, "accounts")).Msg("could not list accounts folder") - return - } - var data []byte - for _, file := range list { - path := filepath.Join(cfg.Server.AccountsDataPath, "accounts", file.Name()) - if data, err = ioutil.ReadFile(path); err != nil { - logger.Error().Err(err).Str("path", path).Msg("could not read account") - continue - } - a := proto.Account{} - if err = json.Unmarshal(data, &a); err != nil { - logger.Error().Err(err).Str("path", path).Msg("could not unmarshal account") - continue - } - logger.Debug().Interface("account", &a).Msg("found account") - if err = s.index.Index(a.Id, &a); err != nil { - logger.Error().Err(err).Str("path", path).Interface("account", &a).Msg("could not index account") - continue - } + if err = s.indexGroups(filepath.Join(cfg.Server.AccountsDataPath, "groups")); err != nil { + return nil, err } // TODO watch folders for new records @@ -194,268 +163,10 @@ type Service struct { index bleve.Index } -// an auth request is currently hardcoded and has to match this regex -// login eq \"teddy\" and password eq \"F&1!b90t111!\" -var authQuery = regexp.MustCompile(`^login eq '(.*)' and password eq '(.*)'$`) // TODO how is ' escaped in the password? - -// ListAccounts implements the AccountsServiceHandler interface -// the query contains account properties -// TODO id vs onpremiseimmutableid -func (s Service) ListAccounts(ctx context.Context, in *proto.ListAccountsRequest, res *proto.ListAccountsResponse) error { - - var password string - - var query query.Query - - // check if this looks like an auth request - match := authQuery.FindStringSubmatch(in.Query) - if len(match) == 3 { - in.Query = fmt.Sprintf("preferred_name eq '%s'", match[1]) // todo fetch email? make query configurable - password = match[2] - if password == "" { - return merrors.BadRequest(s.id, "password must not be empty") - } - } - - if in.Query != "" { - // parse the query like an odata filter - q, err := godata.ParseFilterString(in.Query) - if err != nil { - s.log.Error().Err(err).Msg("could not parse query") - return merrors.InternalServerError(s.id, "could not parse query: %v", err.Error()) - } - - // convert to bleve query - query, err = provider.BuildBleveQuery(q) - if err != nil { - s.log.Error().Err(err).Msg("could not build bleve query") - return merrors.InternalServerError(s.id, "could not build bleve query: %v", err.Error()) - } - } else { - query = bleve.NewMatchAllQuery() - } - - s.log.Debug().Interface("query", query).Msg("using query") - - searchRequest := bleve.NewSearchRequest(query) - var searchResult *bleve.SearchResult - searchResult, err := s.index.Search(searchRequest) - if err != nil { - s.log.Error().Err(err).Msg("could not execute bleve search") - return merrors.InternalServerError(s.id, "could not execute bleve search: %v", err.Error()) - } - - s.log.Debug().Interface("result", searchResult).Msg("result") - - res.Accounts = make([]*proto.Account, 0) - - for _, hit := range searchResult.Hits { - path := filepath.Join(s.Config.Server.AccountsDataPath, "accounts", hit.ID) - - var data []byte - data, err = ioutil.ReadFile(path) - if err != nil { - s.log.Error().Err(err).Str("path", path).Msg("could not read account") - continue - } - a := proto.Account{} - err = json.Unmarshal(data, &a) - if err != nil { - s.log.Error().Err(err).Str("path", path).Msg("could not unmarshal account") - continue - } - s.log.Debug().Interface("account", &a).Msg("found account") - - if password != "" { - if a.PasswordProfile == nil { - s.log.Debug().Interface("account", &a).Msg("no password profile") - return merrors.BadRequest(s.id, "invalid password") - } - if !s.passwordIsValid(a.PasswordProfile.Password, password) { - return merrors.BadRequest(s.id, "invalid password") - } - } - - res.Accounts = append(res.Accounts, &a) - } - - return nil -} - -func (s Service) passwordIsValid(hash string, pwd string) (ok bool) { - defer func() { - if r := recover(); r != nil { - s.log.Error().Err(fmt.Errorf("%s", r)).Str("hash", hash).Msg("password lib panicked") - } - }() - - c := crypt.NewFromHash(hash) - return c.Verify(hash, []byte(pwd)) == nil -} - func cleanupID(id string) (string, error) { id = filepath.Clean(id) if id == "." || strings.Contains(id, "/") { - return "", errors.New("invalid id") + return "", errors.New("invalid id " + id) } return id, nil } - -// GetAccount implements the AccountsServiceHandler interface -func (s Service) GetAccount(c context.Context, req *proto.GetAccountRequest, res *proto.Account) error { - id, err := cleanupID(req.Id) - if err != nil { - return merrors.InternalServerError(s.id, "could not clean up account id: %v", err.Error()) - } - path := filepath.Join(s.Config.Server.AccountsDataPath, "accounts", id) - - var data []byte - data, err = ioutil.ReadFile(path) - if err != nil { - s.log.Error().Err(err).Str("path", path).Msg("could not read account") - return merrors.NotFound(s.id, "account not found") - } - err = json.Unmarshal(data, res) - if err != nil { - s.log.Error().Err(err).Str("path", path).Msg("could not unmarshal account") - return merrors.InternalServerError(s.id, "could not unmarshal account: %v", err.Error()) - } - - s.log.Debug().Interface("account", res).Msg("found account") - return nil -} - -// CreateAccount implements the AccountsServiceHandler interface -func (s Service) CreateAccount(c context.Context, req *proto.CreateAccountRequest, res *proto.Account) error { - var id string - if req.Account == nil { - return merrors.BadRequest(s.id, "account missing") - } - if req.Account.Id == "" { - req.Account.Id = uuid.Must(uuid.NewV4()).String() - } - - id, err := cleanupID(req.Account.Id) - if err != nil { - return merrors.InternalServerError(s.id, "could not clean up account id: %v", err.Error()) - } - path := filepath.Join(s.Config.Server.AccountsDataPath, "accounts", id) - - if req.Account.PasswordProfile != nil && req.Account.PasswordProfile.Password != "" { - // encrypt password - c := crypt.New(crypt.SHA512) - if req.Account.PasswordProfile.Password, err = c.Generate([]byte(req.Account.PasswordProfile.Password), nil); err != nil { - req.Account.PasswordProfile.Password = "***REMOVED***" - s.log.Error().Err(err).Str("id", id).Interface("account", req.Account).Msg("could not hash password") - return merrors.InternalServerError(s.id, "could not hash password: %v", err.Error()) - } - } - req.Account.AccountEnabled = true - - bytes, err := json.Marshal(req.Account) - if err != nil { - s.log.Error().Err(err).Interface("account", req.Account).Msg("could not marshal account") - return merrors.InternalServerError(s.id, "could not marshal account: %v", err.Error()) - } - if err = ioutil.WriteFile(path, bytes, 0600); err != nil { - req.Account.PasswordProfile.Password = "***REMOVED***" - s.log.Error().Err(err).Str("id", id).Str("path", path).Interface("account", req.Account).Msg("could not persist new account") - return merrors.InternalServerError(s.id, "could not persist new account: %v", err.Error()) - } - - if err = s.index.Index(id, req.Account); err != nil { - req.Account.PasswordProfile.Password = "***REMOVED***" - s.log.Error().Err(err).Str("id", id).Str("path", path).Interface("account", req.Account).Msg("could not index new account") - return merrors.InternalServerError(s.id, "could not index new account: %v", err.Error()) - } - - return nil -} - -// UpdateAccount implements the AccountsServiceHandler interface -func (s Service) UpdateAccount(c context.Context, req *proto.UpdateAccountRequest, res *proto.Account) (err error) { - return merrors.InternalServerError(s.id, "not implemented") -} - -// DeleteAccount implements the AccountsServiceHandler interface -func (s Service) DeleteAccount(c context.Context, req *proto.DeleteAccountRequest, res *empty.Empty) error { - id, err := cleanupID(req.Id) - if err != nil { - return merrors.InternalServerError(s.id, "could not clean up account id: %v", err.Error()) - } - path := filepath.Join(s.Config.Server.AccountsDataPath, "accounts", id) - - if err = os.Remove(path); err != nil { - s.log.Error().Err(err).Str("id", id).Str("path", path).Msg("could not remove account") - return merrors.InternalServerError(s.id, "could not remove account: %v", err.Error()) - } - - if err = s.index.Delete(id); err != nil { - s.log.Error().Err(err).Str("id", id).Str("path", path).Msg("could not remove account from index") - return merrors.InternalServerError(s.id, "could not remove account from index: %v", err.Error()) - } - return nil -} - -// ListGroups implements the AccountsServiceHandler interface -func (s Service) ListGroups(c context.Context, req *proto.ListGroupsRequest, res *proto.ListGroupsResponse) (err error) { - return merrors.InternalServerError(s.id, "not implemented") -} - -// GetGroup implements the AccountsServiceHandler interface -func (s Service) GetGroup(c context.Context, req *proto.GetGroupRequest, res *proto.Group) (err error) { - return merrors.InternalServerError(s.id, "not implemented") -} - -// CreateGroup implements the AccountsServiceHandler interface -func (s Service) CreateGroup(c context.Context, req *proto.CreateGroupRequest, res *proto.Group) (err error) { - return merrors.InternalServerError(s.id, "not implemented") -} - -// UpdateGroup implements the AccountsServiceHandler interface -func (s Service) UpdateGroup(c context.Context, req *proto.UpdateGroupRequest, res *proto.Group) (err error) { - return merrors.InternalServerError(s.id, "not implemented") -} - -// DeleteGroup implements the AccountsServiceHandler interface -func (s Service) DeleteGroup(c context.Context, req *proto.DeleteGroupRequest, res *empty.Empty) (err error) { - return merrors.InternalServerError(s.id, "not implemented") -} - -// AddMember implements the AccountsServiceHandler interface -func (s Service) AddMember(c context.Context, req *proto.AddMemberRequest, res *proto.Group) error { - return merrors.InternalServerError(s.id, "not implemented") -} - -// RemoveMember implements the AccountsServiceHandler interface -func (s Service) RemoveMember(c context.Context, req *proto.RemoveMemberRequest, res *proto.Group) error { - return merrors.InternalServerError(s.id, "not implemented") -} - -// ListMembers implements the AccountsServiceHandler interface -func (s Service) ListMembers(c context.Context, req *proto.ListMembersRequest, res *proto.ListMembersResponse) error { - return merrors.InternalServerError(s.id, "not implemented") -} - -// RegisterSettingsBundles pushes the settings bundle definitions for this extension to the ocis-settings service. -func RegisterSettingsBundles(l *log.Logger) { - // TODO this won't work with a registry other than mdns. Look into Micro's client initialization. - // https://github.com/owncloud/ocis-proxy/issues/38 - service := settings.NewBundleService("com.owncloud.api.settings", mclient.DefaultClient) - - requests := []settings.SaveSettingsBundleRequest{ - generateSettingsBundleProfileRequest(), - } - - for i := range requests { - res, err := service.SaveSettingsBundle(context.Background(), &requests[i]) - if err != nil { - l.Err(err). - Msg("Error registering settings bundle") - } else { - l.Info(). - Str("bundle key", res.SettingsBundle.Identifier.BundleKey). - Msg("Successfully registered settings bundle") - } - } -} diff --git a/pkg/service/v0/settings.go b/pkg/service/v0/settings.go index 07f62b91a..6dcf6d1da 100644 --- a/pkg/service/v0/settings.go +++ b/pkg/service/v0/settings.go @@ -1,6 +1,12 @@ package service -import settings "github.com/owncloud/ocis-settings/pkg/proto/v0" +import ( + "context" + + mclient "github.com/micro/go-micro/v2/client" + olog "github.com/owncloud/ocis-pkg/v2/log" + settings "github.com/owncloud/ocis-settings/pkg/proto/v0" +) func generateSettingsBundleProfileRequest() settings.SaveSettingsBundleRequest { return settings.SaveSettingsBundleRequest{ @@ -82,3 +88,26 @@ func generateSettingsBundleProfileRequest() settings.SaveSettingsBundleRequest { }, } } + +// RegisterSettingsBundles pushes the settings bundle definitions for this extension to the ocis-settings service. +func RegisterSettingsBundles(l *olog.Logger) { + // TODO this won't work with a registry other than mdns. Look into Micro's client initialization. + // https://github.com/owncloud/ocis-proxy/issues/38 + service := settings.NewBundleService("com.owncloud.api.settings", mclient.DefaultClient) + + requests := []settings.SaveSettingsBundleRequest{ + generateSettingsBundleProfileRequest(), + } + + for i := range requests { + res, err := service.SaveSettingsBundle(context.Background(), &requests[i]) + if err != nil { + l.Err(err). + Msg("Error registering settings bundle") + } else { + l.Info(). + Str("bundle key", res.SettingsBundle.Identifier.BundleKey). + Msg("Successfully registered settings bundle") + } + } +}