Skip to content
Snippets Groups Projects
Verified Commit 063c4eac authored by Andrej Ramašeuski's avatar Andrej Ramašeuski
Browse files

Plnofunkcni prototyp

parent dd36c22e
Branches
No related tags found
No related merge requests found
Pipeline #10498 passed
0.2.0
0.3.0
......@@ -95,6 +95,8 @@ sub startup( $self ) {
return $c->$cb('Invalid user') if ! $user;
$c->stash->{user} = $user;
$c->stash->{groups} = $jwt->{groups};
$c->stash->{permissions} = $jwt->{permissions};
return $c->$cb();
}
......
......@@ -29,10 +29,8 @@ sub callback ($c) {
$user = $c->schema->resultset('User')->create(\%user);
}
$c->session->{user} = {
$user->get_columns,
token => $user->api_token({ secret => $c->cfg->{jwt_secret}}),
};
my @groups = ();
my $permissions = {};
my $groups = $c->schema->resultset('Group')->search(
{ octid => { '-in' => $octopus_user->{groups} }},
......@@ -41,15 +39,24 @@ sub callback ($c) {
GROUP:
while ( my $group = $groups->next ) {
push @{$c->session->{user}{groups}}, $group->id;
if ( $group->permissions ) {
PERMISSION:
foreach my $permission ( @{ $group->permissions } ) {
$c->session->{user}{permissions}{$permission} = 1;
}
push @groups, $group->id;
foreach my $permission ( @{ $group->permissions || [] } ) {
$permissions->{$permission} = 1;
}
}
$c->session->{user} = {
$user->get_columns,
groups => \@groups,
permissions => $permissions,
api_token => $user->api_token({
secret => $c->cfg->{jwt_secret},
permissions => $permissions,
groups => \@groups,
}),
};
$c->authenticate();
$c->redirect_to('/');
}
......
......@@ -11,8 +11,11 @@ sub create($c) {
$c->openapi->valid_input or return;
my $args = $c->req->json;
return $c->error(403, 'Access denied') if ! $c->stash->{permissions}{create};
my $exists = $c->schema->resultset('Meet')->count({
name => $args->{name}
deleted => undef,
name => $args->{name},
});
return $c->error(400, 'DUPLICTE_NAME') if $exists;
......@@ -43,11 +46,7 @@ sub get($c) {
$c->openapi->valid_input or return;
my $args = $c->req->json;
my $meet = $c->schema->resultset('Meet')->find({
id => $c->stash->{id}
});
return $c->error(404, 'NOT_FOUND') if ! $meet;
my $meet = $c->_get($c->stash->{id}, 0) // return;
$c->render(openapi => $c->spec_filter({
$meet->get_columns,
......@@ -63,11 +62,15 @@ sub list($c) {
my $meets = $c->schema->resultset('Meet')->search({
deleted => undef,
-or => [
owner_id => $c->stash->{user}->id,
# PODMINKA PRO UCASTNIKY
"groups.group_id" => { '-in' => $c->stash->{groups} },
]
},
{
order_by => 'name',
join => 'groups',
distinct => 1,
}
);
......@@ -95,12 +98,7 @@ sub add_groups($c) {
$c->openapi->valid_input or return;
my $args = $c->req->json;
my $meet = $c->schema->resultset('Meet')->find({
id => $c->stash->{id}
});
return $c->error(404, 'NOT_FOUND') if ! $meet;
return $c->error(403, 'ACCESS_DENIED') if $meet->owner_id != $c->stash->{user}->id;
my $meet = $c->_get($c->stash->{id}, 1) // return;
IDS:
foreach my $id ( @{ $args->{groups} } ) {
......@@ -117,12 +115,7 @@ sub add_moderators($c) {
$c->openapi->valid_input or return;
my $args = $c->req->json;
my $meet = $c->schema->resultset('Meet')->find({
id => $c->stash->{id}
});
return $c->error(404, 'NOT_FOUND') if ! $meet;
return $c->error(403, 'ACCESS_DENIED') if $meet->owner_id != $c->stash->{user}->id;
my $meet = $c->_get($c->stash->{id}, 1) // return;
IDS:
foreach my $user ( @{ $args->{users} } ) {
......@@ -142,12 +135,7 @@ sub add_moderators($c) {
sub delete_group($c) {
$c->openapi->valid_input or return;
my $meet = $c->schema->resultset('Meet')->find({
id => $c->stash->{id}
});
return $c->error(404, 'NOT_FOUND') if ! $meet;
return $c->error(403, 'ACCESS_DENIED') if $meet->owner_id != $c->stash->{user}->id;
my $meet = $c->_get($c->stash->{id}, 1) // return;
$meet->delete_related('meet_groups',
{ group_id => $c->stash->{group_id} }
......@@ -160,12 +148,7 @@ sub delete_group($c) {
sub delete_moderator($c) {
$c->openapi->valid_input or return;
my $meet = $c->schema->resultset('Meet')->find({
id => $c->stash->{id}
});
return $c->error(404, 'NOT_FOUND') if ! $meet;
return $c->error(403, 'ACCESS_DENIED') if $meet->owner_id != $c->stash->{user}->id;
my $meet = $c->_get($c->stash->{id}, 1) // return;
$meet->delete_related('moderators',
{ octid => $c->stash->{user_id} }
......@@ -178,19 +161,36 @@ sub delete_moderator($c) {
sub delete($c) {
$c->openapi->valid_input or return;
my $meet = $c->schema->resultset('Meet')->find({
id => $c->stash->{id}
my $meet = $c->_get($c->stash->{id}, 1) // return;
$meet->update({ deleted => \'now()'});
$c->render( status => 204, text => '' );
}
sub update($c) {
$c->openapi->valid_input or return;
my $args = $c->req->json;
my $meet = $c->_get($c->stash->{id}, 1) // return;
my $exists = $c->schema->resultset('Meet')->count({
id => { '!=' => $meet->id },
deleted => undef,
name => $args->{name},
});
return $c->error(404, 'NOT_FOUND') if ! $meet;
return $c->error(403, 'ACCESS_DENIED') if $meet->owner_id != $c->stash->{user}->id;
return $c->error(400, 'DUPLICTE_NAME') if $exists;
$meet->update({ deleted => \'now()'});
$meet->update({
name => $args->{name},
description => $args->{description},
});
$c->render( status => 204, text => '' );
}
sub meet($c) {
sub meet($c) { #NENI API!
my $meet = $c->schema->resultset('Meet')->find({
id => $c->stash->{id}
......@@ -210,5 +210,20 @@ sub meet($c) {
$c->render('meet');
}
sub _get($c, $id, $for_owner) {
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;
}
return $meet;
}
1;
......@@ -57,6 +57,8 @@ sub api_token {
secret => $args->{secret},
claims => {
id => $self->id,
groups => $args->{groups},
permissions => $args->{permissions},
exp => $exp,
}
)->encode;
......@@ -76,6 +78,14 @@ sub meet_token {
'.jpg',
);
my $moderator = 0;
$moderator = 1 if $meet->owner_id == $self->id;
$moderator ||= $meet->moderators({
octid => $self->octid
})->count;
return Mojo::JWT->new(
secret => $cfg->{jitsi_secret},
claims => {
......@@ -83,7 +93,7 @@ sub meet_token {
iss => 'semeet',
sub => 'meet.pirati.cz',
room => $meet->uuid,
# moderator => $user{moderator} ? \1:\0,
moderator => $moderator ? \1:\0,
exp => time + MEET_TOKEN_LIFETIME,
context => {
user => {
......
......@@ -163,6 +163,41 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/Meet'
put:
x-mojo-to: meets#update
security:
- Bearer: []
tags:
- meets
summary: "Aktualizovat mistnost"
operationId: updateMeet
parameters:
- name: id
in: path
required: true
example: 100345
description: "Identifikator mistnosti"
schema:
type: integer
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
name:
type: string
example: "Republikový vybor"
description:
type: string
example: "Místnost pro uzavřená jednáni RV"
required:
- name
responses:
204:
description: Mistnost je aktualizovana
delete:
x-mojo-to: meets#delete
security:
......
{
name => 'SeMeet',
description => 'Secured Jitsi Meet',
description => 'Bezpečný Jitsi Meet s pirátskou identitou',
database => {
dsn => $ENV{CFG_DB_DSN},
user => $ENV{CFG_DB_USERNAME},
......
<form id="Meet" @submit.prevent="updateMeet">
<form>
<div class="form-field form-field--error form-field--required mb-4">
<label class="form-field__label" for="name"><%=l 'INPUT_MEET_NAME_LABEL' %></label>
......@@ -11,18 +11,18 @@
<div class="form-field mb-4">
<label class="form-field__label" for="description"><%=l 'INPUT_MEET_DESCRIPTION_LABEL' %></label>
<div class="form-field__wrapper form-field__wrapper--shadowed">
<textarea class="text-input form-field__control " value="" rows="5" cols="40" placeholder="<%=l 'INPUT_MEET_DESCRIPTION_PLACEHOLDER' %>" id="description">{{ meet.description }}</textarea>
<textarea class="text-input form-field__control " value="" rows="5" cols="40" placeholder="<%=l 'INPUT_MEET_DESCRIPTION_PLACEHOLDER' %>" id="description" v-model="meet.description"></textarea>
</div>
</div>
<button class="btn btn--blue-300 btn--hoveractive">
<button class="btn btn--blue-300 btn--hoveractive" @click.prevent="updateMeet">
<div class="btn__body"><%=l 'Save changes' %></div>
</button>
<button class="btn btn--red-600 btn--hoveractive" @click="delete_confirm_visible=true">
<button class="btn btn--red-600 btn--hoveractive" @click.prevent="delete_confirm_visible=true">
<div class="btn__body"><%=l 'Delete meet' %></div>
</button>
<form>
</form>
<div class="modal__overlay toggle-modal-sample-1" id="modal-sample-1" v-if="delete_confirm_visible">
<div class="modal__content" role="dialog">
......
......@@ -9,7 +9,11 @@
</div>
<div>
<h1 class="head-alt-xl">Opravdu bezpečný jitsi</h1>
<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-xl text-red-600">Testovací provoz</h1>
</div>
</div>
......@@ -39,7 +39,7 @@
<a href="/">
<img src="<%= config->{styleguide} %>/images/logo-round-white.svg" class="w-8" />
</a>
<span class="pl-4 font-bold text-xl lg:pr-8"><a href="/"><%= config->{name} %></a></span>
<span class="pl-4 font-bold text-xl lg:pr-8"><a href="/"><%= config->{name} %> - <%= config->{description} %></a></span>
</div>
<div class="navbar__menutoggle my-4 flex justify-end lg:hidden">
<a href="#" @click="show = !show" class="no-underline hover:no-underline">
......
% layout 'default';
<h1 class="head-alt-md mb-8"><%= $meet->name %></h1>
<h1 class="head-alt-md mb-8" v-cloak>{{ meet.name }}</h1>
%= include 'includes/meet'
% if ( $is_editable ) {
<div class="grid grid-cols-4 border border-b-0 divide-x text-center">
<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='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>
<div class="border p-4" v-effect="getMeet()">
<div class="border p-4" v-effect="getMeet()" v-cloak>
<div v-if="active_tab == 'form'">
%= include 'includes/meet_form'
</div>
......@@ -33,6 +33,11 @@
const MEET_URL = '/api/meets/<%= stash->{id} %>';
const ADD_GROUPS_URL = '/api/meets/<%= stash->{id} %>/group';
const ADD_USERS_URL = '/api/meets/<%= stash->{id} %>/moderator';
const API_HEADERS = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer <%= current_user->{api_token} %>",
};
createApp({
......@@ -63,9 +68,7 @@
getMeet() {
fetch(MEET_URL, {
headers: {
"Authorization": "Bearer <%= current_user->{token} %>",
},
headers: API_HEADERS,
})
.then((res) => res.json())
.then(res => {
......@@ -76,9 +79,11 @@
updateMeet() {
fetch(MEET_URL, {
method: "PUT",
headers: {
"Authorization": "Bearer <%= current_user->{token} %>",
},
headers: API_HEADERS,
body: JSON.stringify({
name: this.meet.name,
description: this.meet.description,
}),
})
.then()
},
......@@ -103,11 +108,7 @@
fetch(ADD_GROUPS_URL, {
method: "POST",
headers: {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer <%= current_user->{token} %>",
},
headers: API_HEADERS,
body: JSON.stringify({ groups: this.selected_groups }),
})
.then((response) => {
......@@ -122,11 +123,7 @@
removeGroup(id) {
fetch(MEET_URL + '/group/' + id, {
method: "DELETE",
headers: {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer <%= current_user->{token} %>",
},
headers: API_HEADERS,
})
.then((response) => {
if (response.ok) {
......@@ -157,11 +154,7 @@
fetch(ADD_USERS_URL, {
method: "POST",
headers: {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer <%= current_user->{token} %>",
},
headers: API_HEADERS,
body: JSON.stringify({ users: selected }),
})
.then((response) => {
......@@ -176,11 +169,7 @@
removeModerator(id) {
fetch(MEET_URL + '/moderator/' + id, {
method: "DELETE",
headers: {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer <%= current_user->{token} %>",
},
headers: API_HEADERS,
})
.then((response) => {
if (response.ok) {
......@@ -192,16 +181,10 @@
deleteMeet() {
fetch(MEET_URL, {
method: "DELETE",
headers: {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer <%= current_user->{token} %>",
},
headers: API_HEADERS,
})
.then( response => {
this.delete_confirm_visible = false;
window.location.replace("/");
// redirect
})
.catch(() => {
this.formError = "<%=l 'ERROR_SERVERSIDE' %>"
......
% layout 'default';
<div v-effect="fetchData()" class="grid grid-cols-2 md:grid-cols-3 gap-4">
<div v-effect="fetchData()" class="grid grid-cols-2 md:grid-cols-3 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">
<h2 class="head-alt-xs"><a v-bind:href="'/meets/' + meet.id">{{meet.name}}</a></h2>
<div>
%# <a class="hover:no-underline" v-bind:href="'/meets/' + meet.id" title="<%=l 'ENTER' %>"><i class="ico--phone"></i></a>
</div>
</div>
<div class="text-xs" v-if="meet.groups.length > 0">
......@@ -22,7 +19,7 @@
</div>
% if ( current_user->{permissions}{create} ) {
<form @submit.prevent="submitForm">
<form @submit.prevent="submitForm" v-cloak>
<div class="card elevation-4 space-y-4 mt-2">
<div class="card__body">
<div class="grid grid-cols-4 gap-4">
......@@ -44,6 +41,11 @@
import { createApp } from 'https://cdn-unpkg.pirati.cz/petite-vue@0.2.2/dist/petite-vue.es.js'
const BASE_URL = "/api/meets";
const API_HEADERS = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer <%= current_user->{api_token} %>",
};
createApp({
meets: [],
......@@ -52,15 +54,9 @@
name: ""
},
// async copyLink(id) {
// await navigator.clipboard.writeText('<%= config->{base_url} %>/meets/' + id);
// },
fetchData() { //TODO: async
fetch(BASE_URL, {
headers: {
"Authorization": "Bearer <%= current_user->{token} %>",
},
headers: API_HEADERS,
})
.then((res) => res.json())
.then(res => {
......@@ -79,11 +75,7 @@
fetch(BASE_URL, {
method: "POST",
headers: {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer <%= current_user->{token} %>",
},
headers: API_HEADERS,
body: JSON.stringify(this.formData),
})
.then( response => {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment