From ba260925715e5c081d1cddaa53ba2e20161e378c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrej=20Rama=C5=A1euski?= <andrej@x2.cz> Date: Tue, 29 Nov 2022 23:28:38 +0100 Subject: [PATCH] Korekce opravneni --- lib/SeMeet/Controller/Meets.pm | 47 ++++++---- lib/SeMeet/I18N/cs.pm | 1 + lib/SeMeet/Schema/Result/Meet.pm | 13 +++ openapi.yaml | 2 - script/sync_octopus_groups | 21 +++++ templates/includes/meet_groups.html.ep | 5 +- templates/includes/meet_moderators.html.ep | 5 +- templates/index.html.ep | 2 +- templates/meet.html.ep | 101 +++++++++++---------- templates/meets.html.ep | 16 +++- 10 files changed, 139 insertions(+), 74 deletions(-) diff --git a/lib/SeMeet/Controller/Meets.pm b/lib/SeMeet/Controller/Meets.pm index 6bbd904..27935af 100644 --- a/lib/SeMeet/Controller/Meets.pm +++ b/lib/SeMeet/Controller/Meets.pm @@ -47,12 +47,12 @@ sub get($c) { my $args = $c->req->json; my $meet = $c->_get($c->stash->{id}, 0) // return; + my $is_mod = $meet->moderators({ octid => $c->stash->{user}->id})->count; $c->render(openapi => $c->spec_filter({ $meet->get_columns, - groups => $meet->cached_groups, - moderators => $meet->cached_moderators, - is_editable => ( $meet->owner_id == $c->stash->{user}->id), + groups => $meet->cached_groups, + moderators => $meet->cached_moderators, }, 'Meet')); } @@ -65,11 +65,12 @@ sub list($c) { -or => [ owner_id => $c->stash->{user}->id, "groups.group_id" => { '-in' => $c->stash->{groups} }, + "moderators.octid" => $c->stash->{user}->octid, ] }, { order_by => 'name', - join => 'groups', + join => ['groups', 'moderators'], distinct => 1, } ); @@ -82,7 +83,8 @@ sub list($c) { $meet->get_columns, groups => $meet->cached_groups, moderators => $meet->cached_moderators, - is_editable => ( $meet->owner_id == $c->stash->{user}->id), +# is_owned => ( $meet->owner_id == $c->stash->{user}->id), +# is_moderated => 0, }, 'Meet') } @@ -115,7 +117,7 @@ sub add_moderators($c) { $c->openapi->valid_input or return; my $args = $c->req->json; - my $meet = $c->_get($c->stash->{id}, 1) // return; + my $meet = $c->_get($c->stash->{id}, 2) // return; IDS: foreach my $user ( @{ $args->{users} } ) { @@ -148,7 +150,7 @@ sub delete_group($c) { sub delete_moderator($c) { $c->openapi->valid_input or return; - my $meet = $c->_get($c->stash->{id}, 1) // return; + my $meet = $c->_get($c->stash->{id}, 2) // return; $meet->delete_related('moderators', { octid => $c->stash->{user_id} } @@ -161,7 +163,7 @@ sub delete_moderator($c) { sub delete($c) { $c->openapi->valid_input or return; - my $meet = $c->_get($c->stash->{id}, 1) // return; + my $meet = $c->_get($c->stash->{id}, 2) // return; $meet->update({ deleted => \'now()'}); @@ -172,7 +174,7 @@ sub update($c) { $c->openapi->valid_input or return; my $args = $c->req->json; - my $meet = $c->_get($c->stash->{id}, 1) // return; + my $meet = $c->_get($c->stash->{id}, 2) // return; my $exists = $c->schema->resultset('Meet')->count({ id => { '!=' => $meet->id }, @@ -201,25 +203,32 @@ sub meet($c) { #NENI API! }); return $c->error(404, 'NOT_FOUND') if ! $meet; - # CHECK MEET ACCESS - $c->stash->{is_editable} = ( $meet->owner_id == $user->id); - $c->stash->{token} = $user->meet_token($meet, $c->config); + my $roles = $meet->user_roles($user, $c->current_user->{groups}); + + return $c->error(404, 'NOT_FOUND') if ! $roles->{any}; + $c->stash->{meet} = $meet; + $c->stash->{roles} = $roles; + $c->stash->{token} = $user->meet_token($meet, $c->config); $c->render('meet'); } -sub _get($c, $id, $for_owner) { - - my $meet = $c->schema->resultset('Meet')->find({ - id => $id - }); +sub _get($c, $id, $access) { + my $meet = $c->schema->resultset('Meet')->find({ id => $id }); return $c->error(404, 'NOT_FOUND') if ! $meet; - if ( $for_owner ) { - return $c->error(403, 'ACCESS_DENIED') if $meet->owner_id != $c->stash->{user}->id; + my $roles = $meet->user_roles($c->stash->{user}, $c->stash->{groups}); + return $c->error(403, 'ACCESS_DENIED') if ! $roles->{any}; + + if ( $access == 1 && ! ($roles->{moderator} || $roles->{owner}) ) { + return $c->error(403, 'ACCESS_DENIED'); + } + + if ( $access == 2 && ! $roles->{owner} ) { + return $c->error(403, 'ACCESS_DENIED'); } return $meet; diff --git a/lib/SeMeet/I18N/cs.pm b/lib/SeMeet/I18N/cs.pm index 48fb158..207ecc6 100644 --- a/lib/SeMeet/I18N/cs.pm +++ b/lib/SeMeet/I18N/cs.pm @@ -23,6 +23,7 @@ our %Lexicon = ( ENTER => 'Vstoupit', COPY_LINK => 'ZkopÃrovat odkaz', + 'About meet' => 'O mistnosti', 'Add groups' => 'PÅ™idat skupiny', 'Add moderators' => 'PÅ™idat moderatory', 'Create meet' => 'VytvoÅ™it mÃstnost', diff --git a/lib/SeMeet/Schema/Result/Meet.pm b/lib/SeMeet/Schema/Result/Meet.pm index 3fb4899..991a547 100644 --- a/lib/SeMeet/Schema/Result/Meet.pm +++ b/lib/SeMeet/Schema/Result/Meet.pm @@ -65,6 +65,19 @@ __PACKAGE__->inflate_column('properties', { deflate => sub { to_json(shift); }, }); +sub user_roles($self, $user, $groups) { + + my $roles = { + participant => $self->meet_groups({ group_id => { -in => $groups } })->count(), + moderator => $self->moderators({ octid => $user->octid })->count(), + owner => ($self->owner_id == $user->id), + }; + + $roles->{any} = $roles->{participant} || $roles->{moderator} || $roles->{owner}; + + return $roles; +} + sub update_groups_cache($self) { my @groups = (); foreach my $group ($self->groups) { diff --git a/openapi.yaml b/openapi.yaml index bfb8c46..ee4791b 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -48,8 +48,6 @@ components: type: array items: $ref: '#/components/schemas/UserInList' - is_editable: - type: boolean GroupInList: type: object properties: diff --git a/script/sync_octopus_groups b/script/sync_octopus_groups index 4b65439..f018fec 100755 --- a/script/sync_octopus_groups +++ b/script/sync_octopus_groups @@ -27,8 +27,16 @@ my $schema = SeMeet::Schema->connect({ my $octopus_groups = $iapi->get('octopus/groups/'); +my @exists = (); + +my $guard = $schema->txn_scope_guard; + +# Insert/Update GROUP: foreach my $group ( @{ $octopus_groups } ) { + + push @exists, $group->{id}; + $schema->resultset('Group')->update_or_create( { octid => $group->{id}, @@ -37,3 +45,16 @@ foreach my $group ( @{ $octopus_groups } ) { { key => 'octid'} ); } + +# Cleanup +$schema->resultset('Group')->search({octid => {-not_in => \@exists}})->delete; + +# Update cache +my $meets = $schema->resultset('Meet')->search({deleted => undef}); + +MEET: +while ( my $meet = $meets->next ) { + $meet->update_groups_cache(); +} + +$guard->commit; diff --git a/templates/includes/meet_groups.html.ep b/templates/includes/meet_groups.html.ep index bd0c2b7..29545c3 100644 --- a/templates/includes/meet_groups.html.ep +++ b/templates/includes/meet_groups.html.ep @@ -1,12 +1,15 @@ <div class="mb-4"> <span v-for="group in meet.groups" class="chip chip--green-400 mr-1 mb-1 rounded"> {{ group.name }} +% if ( $roles->{owner} || $roles->{moderator} ) { <span class="icon"> <i class="ico--cross ml-3 cursor-pointer" @click="removeGroup(group.id)"></i> </span> +% } </span> </div> +% if ( $roles->{owner} || $roles->{moderator} ) { <div class="" v-effect="searchGroups()"> <label class="form-field__label" for="name"><%=l 'LABEL_GROUPS_ADD' %></label> <input type="text" class="w-full text-input" value="" v-model="search_groups" id="search_group" placeholder="<%=l 'INPUT_MEET_ADD_GROUPS_PLACEHOLDER' %>"/> @@ -22,4 +25,4 @@ </button> </div> </div> - +% } diff --git a/templates/includes/meet_moderators.html.ep b/templates/includes/meet_moderators.html.ep index b1fd196..a6ed190 100644 --- a/templates/includes/meet_moderators.html.ep +++ b/templates/includes/meet_moderators.html.ep @@ -1,12 +1,15 @@ <div class="mb-4"> <span v-for="moderator in meet.moderators" class="chip chip--red-600 mr-1 mb-1 rounded"> {{ moderator.name }} +% if ( $roles->{owner} ) { <span class="icon"> <i class="ico--cross ml-3 cursor-pointer" @click="removeModerator(moderator.id)"></i> </span> +% } </span> </div> +% if ( $roles->{owner} ) { <div v-effect="searchUsers()"> <label class="form-field__label" for="name"><%=l 'LABEL_USERS_ADD' %></label> <input type="text" class="w-full text-input" value="" v-model="search_users" id="search_user" placeholder="<%=l 'INPUT_MEET_ADD_USERS_PLACEHOLDER' %>"/> @@ -22,4 +25,4 @@ </button> </div> </div> - +% } diff --git a/templates/index.html.ep b/templates/index.html.ep index 8b2ae83..a4055a3 100644 --- a/templates/index.html.ep +++ b/templates/index.html.ep @@ -12,7 +12,7 @@ <h1 class="head-alt-lg">Opravdu bezpeÄný jitsi</h1> <h1 class="head-alt-lg text-green-400">Žádnà náhodnà moderatoÅ™i</h1> <h1 class="head-alt-lg text-violet-400">VÅ¡echno je pod kontrolou</h1> -<h1 class="head-alt-lg text-blue-300">Vždy vÃÅ¡ s kým mluvÃÅ¡</h1> +<h1 class="head-alt-lg text-blue-300">Vždy vÃÅ¡ kdo tÄ› poslouchá</h1> <h1 class="head-alt-xl text-red-600">Testovacà provoz</h1> </div> </div> diff --git a/templates/meet.html.ep b/templates/meet.html.ep index b8973f3..2186586 100644 --- a/templates/meet.html.ep +++ b/templates/meet.html.ep @@ -3,18 +3,14 @@ %= include 'includes/meet' -% if ( $is_editable ) { <div class="grid grid-cols-3 border border-b-0 divide-x text-center"> <div @click="active_tab='groups'" class="p-4 bg-grey-125" :class="tabClass('groups')"><%=l 'Authorized groups' %></div> <div @click="active_tab='moderators'" class="p-4 bg-grey-125" :class="tabClass('moderators')"><%=l 'Moderators' %></div> %#<div @click="active_tab='invites'" class="p-4 bg-grey-125" :class="tabClass('invites')"><%=l 'Invites' %></div> -<div @click="active_tab='form'" class="p-4 bg-grey-125" :class="tabClass('form')"><%=l 'Configuration' %></div> +<div @click="active_tab='form'" class="p-4 bg-grey-125" :class="tabClass('form')"><%=l $roles->{owner} ? 'Configuration':'About meet' %></div> </div> <div class="border p-4" v-effect="getMeet()" v-cloak> - <div v-if="active_tab == 'form'"> -%= include 'includes/meet_form' - </div> <div v-if="active_tab == 'groups'"> %= include 'includes/meet_groups' </div> @@ -23,6 +19,13 @@ </div> <div v-if="active_tab == 'invites'"> </div> + <div v-if="active_tab == 'form'"> +% if ( $roles->{owner} ) { +%= include 'includes/meet_form' +% } else { +<%= $meet->description %> +% } + </div> </div> <script type="module"> @@ -76,6 +79,8 @@ }) }, +% if ( $roles->{owner} ) { + updateMeet() { fetch(MEET_URL, { method: "PUT", @@ -88,40 +93,55 @@ .then() }, - searchGroups() { - if ( this.search_groups.length < 2 ) { - this.groups = []; + searchUsers() { + if ( this.search_users.length < 2 ) { + this.users = []; return true; } - fetch(GROUPS_URL + '?search=' + this.search_groups ) + fetch(USERS_URL + '?search=' + this.search_users ) .then((res) => res.json()) .then(res => { - this.groups = res; + this.users = res; }) }, - addGroups() { - if ( this.selected_groups.length == 0) { + deleteMeet() { + fetch(MEET_URL, { + method: "DELETE", + headers: API_HEADERS, + }) + .then( response => { + window.location.replace("/"); + }) + .catch(() => { + this.formError = "<%=l 'ERROR_SERVERSIDE' %>" + }); + }, + + addModerators() { + if ( this.selected_users.length == 0) { return true; } - fetch(ADD_GROUPS_URL, { + const selected = this.users.filter(item => this.selected_users.includes(item.id)) + + fetch(ADD_USERS_URL, { method: "POST", headers: API_HEADERS, - body: JSON.stringify({ groups: this.selected_groups }), + body: JSON.stringify({ users: selected }), }) .then((response) => { if (response.ok) { - this.selected_groups =[] - this.search_groups = '' + this.selected_users =[] + this.search_users = '' this.getMeet() } }) }, - removeGroup(id) { - fetch(MEET_URL + '/group/' + id, { + removeModerator(id) { + fetch(MEET_URL + '/moderator/' + id, { method: "DELETE", headers: API_HEADERS, }) @@ -132,42 +152,43 @@ }) }, - searchUsers() { - if ( this.search_users.length < 2 ) { - this.users = []; +% } + +% if ( $roles->{owner} || $roles->{moderator} ) { + searchGroups() { + if ( this.search_groups.length < 2 ) { + this.groups = []; return true; } - fetch(USERS_URL + '?search=' + this.search_users ) + fetch(GROUPS_URL + '?search=' + this.search_groups ) .then((res) => res.json()) .then(res => { - this.users = res; + this.groups = res; }) }, - addModerators() { - if ( this.selected_users.length == 0) { + addGroups() { + if ( this.selected_groups.length == 0) { return true; } - const selected = this.users.filter(item => this.selected_users.includes(item.id)) - - fetch(ADD_USERS_URL, { + fetch(ADD_GROUPS_URL, { method: "POST", headers: API_HEADERS, - body: JSON.stringify({ users: selected }), + body: JSON.stringify({ groups: this.selected_groups }), }) .then((response) => { if (response.ok) { - this.selected_users =[] - this.search_users = '' + this.selected_groups =[] + this.search_groups = '' this.getMeet() } }) }, - removeModerator(id) { - fetch(MEET_URL + '/moderator/' + id, { + removeGroup(id) { + fetch(MEET_URL + '/group/' + id, { method: "DELETE", headers: API_HEADERS, }) @@ -178,20 +199,8 @@ }) }, - deleteMeet() { - fetch(MEET_URL, { - method: "DELETE", - headers: API_HEADERS, - }) - .then( response => { - window.location.replace("/"); - }) - .catch(() => { - this.formError = "<%=l 'ERROR_SERVERSIDE' %>" - }); - } +% } }).mount() </script> -% } diff --git a/templates/meets.html.ep b/templates/meets.html.ep index a4d5aa9..78120ca 100644 --- a/templates/meets.html.ep +++ b/templates/meets.html.ep @@ -1,19 +1,28 @@ % layout 'default'; -<div v-effect="fetchData()" class="grid grid-cols-2 md:grid-cols-3 gap-4" v-cloak> +<div v-effect="fetchData()" class="grid grid-cols-1 md:grid-cols-2 gap-4" v-cloak> <div v-for="meet in meets" class="card elevation-4"> <div class="card__body"> - <div class="flex justify-between mb-3"> + <div class="flex justify-between mb-2 border-b border-dotted border-grey-300"> <h2 class="head-alt-xs"><a v-bind:href="'/meets/' + meet.id">{{meet.name}}</a></h2> </div> - <div class="text-xs" v-if="meet.groups.length > 0"> + <div class="text-xs mb-2" v-if="meet.description">{{ meet.description }}</div> + + <div class="text-xs mb-2" v-if="meet.groups.length > 0"> <strong><%=l 'Authorized groups' %>:</strong> <span v-for="(group, index) in meet.groups" class="text-grey-300"> {{ group.name }}<span v-if="index != meet.groups.length - 1">, </span> </span> </div> + <div class="text-xs mb-2" v-if="meet.moderators.length > 0"> + <strong><%=l 'Moderators' %>:</strong> + <span v-for="(moderator, index) in meet.moderators" class="text-grey-300"> + {{ moderator.name }}<span v-if="index != meet.moderators.length - 1">, </span> + </span> + </div> + </div> </div> </div> @@ -99,4 +108,3 @@ }).mount() </script> - -- GitLab