fix: leave workspace + instance api

This commit is contained in:
Ruben Fiszel
2023-11-18 15:07:06 +01:00
parent 36379d6db0
commit ee243dedc6
9 changed files with 187 additions and 48 deletions
@@ -0,0 +1,15 @@
{
"db_name": "PostgreSQL",
"query": "DELETE FROM usr WHERE workspace_id = $1 AND email = $2",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text",
"Text"
]
},
"nullable": []
},
"hash": "00be497354f5375e9ccffb998d126a853da91d607ff9e57e10d0e5481e4d3848"
}
+30 -16
View File
@@ -731,6 +731,20 @@ paths:
schema:
type: string
/users/leave_instance:
post:
summary: leave instance
operationId: leaveInstance
tags:
- user
responses:
"200":
description: status
content:
text/plain:
schema:
type: string
/users/usage:
get:
summary: get current usage outside of premium workspaces
@@ -827,22 +841,6 @@ paths:
schema:
$ref: "#/components/schemas/User"
/w/{workspace}/users/leave_workspace:
post:
summary: leave workspace
operationId: leaveWorkspace
tags:
- user
parameters:
- $ref: "#/components/parameters/WorkspaceId"
responses:
"200":
description: status
content:
text/plain:
schema:
type: string
/users/accept_invite:
post:
summary: accept invite to workspace
@@ -1051,6 +1049,22 @@ paths:
schema:
type: string
/w/{workspace}/workspaces/leave:
post:
summary: leave workspace
operationId: leaveWorkspace
tags:
- workspace
parameters:
- $ref: "#/components/parameters/WorkspaceId"
responses:
"200":
description: status
content:
text/plain:
schema:
type: string
/w/{workspace}/users/whois/{username}:
get:
summary: whois
+24
View File
@@ -94,6 +94,7 @@ pub fn global_service() -> Router {
"/tutorial_progress",
post(update_tutorial_progress).get(get_tutorial_progress),
)
.route("/leave_instance", post(leave_instance))
// .route("/list_invite_codes", get(list_invite_codes))
// .route("/create_invite_code", post(create_invite_code))
// .route("/signup", post(signup))
@@ -1416,6 +1417,29 @@ async fn add_user_to_workspace<'c>(
Ok(tx)
}
async fn leave_instance(
Extension(db): Extension<DB>,
ApiAuthed { email, username, .. }: ApiAuthed,
) -> Result<String> {
let mut tx = db.begin().await?;
sqlx::query!("DELETE FROM password WHERE email = $1", &email)
.execute(&mut *tx)
.await?;
audit_log(
&mut *tx,
&username,
"workspaces.leave",
ActionKind::Delete,
"global",
Some(&email),
None,
)
.await?;
tx.commit().await?;
Ok(format!("Left instance",))
}
async fn update_workspace_user(
ApiAuthed { username, is_admin, .. }: ApiAuthed,
Extension(db): Extension<DB>,
+27 -1
View File
@@ -83,7 +83,8 @@ pub fn workspaced_service() -> Router {
.route("/edit_copilot_config", post(edit_copilot_config))
.route("/get_copilot_info", get(get_copilot_info) )
.route("/edit_error_handler", post(edit_error_handler))
.route("/edit_large_file_storage_config", post(edit_large_file_storage_config));
.route("/edit_large_file_storage_config", post(edit_large_file_storage_config))
.route("/leave", post(leave_workspace));
#[cfg(feature = "enterprise")]
{
@@ -1306,6 +1307,31 @@ async fn archive_workspace(
Ok(format!("Archived workspace {}", &w_id))
}
async fn leave_workspace(
Extension(db): Extension<DB>,
Path(w_id): Path<String>,
ApiAuthed { email, username, .. }: ApiAuthed,
) -> Result<String> {
let mut tx = db.begin().await?;
sqlx::query!("DELETE FROM usr WHERE workspace_id = $1 AND email = $2", &w_id, &email)
.execute(&mut *tx)
.await?;
audit_log(
&mut *tx,
&username,
"workspaces.leave",
ActionKind::Delete,
&w_id,
Some(&email),
None,
)
.await?;
tx.commit().await?;
Ok(format!("Left workspace {}", &w_id))
}
async fn unarchive_workspace(
Extension(db): Extension<DB>,
Path(w_id): Path<String>,
-1
View File
@@ -1847,7 +1847,6 @@ async fn spawn_dedicated_worker(
mpsc::channel::<Arc<QueuedJob>>(MAX_BUFFERED_DEDICATED_JOBS);
let mut killpill_rx = killpill_rx.resubscribe();
let db = db.clone();
let worker_dir = worker_dir.clone();
let base_internal_url = base_internal_url.to_string();
let worker_name = worker_name.to_string();
let job_completed_tx = job_completed_tx.clone();
@@ -145,7 +145,7 @@
{/if}
<div class="grid grid-cols-2 pt-8 pb-1">
<h2 class="py-0 my-0 border-b">Tokens</h2>
<h2 class="py-0 my-0 border-b pt-3">Tokens</h2>
<div class="flex justify-end border-b pb-1">
<Button
size="sm"
@@ -263,7 +263,7 @@
tooltip="Manage invites on your workspace."
documentationLink="https://www.windmill.dev/docs/core_concepts/authentification#adding-users-to-a-workspace"
>
<div class="flex gap-8">
<div class="flex gap-8 items-center">
{#if auto_invite_domain != undefined}
<Toggle
size="xs"
@@ -1,6 +1,6 @@
<script lang="ts">
import MenuLink from './MenuLink.svelte'
import { superadmin, userStore } from '$lib/stores'
import { superadmin, userStore, workspaceStore } from '$lib/stores'
import { SIDEBAR_SHOW_SCHEDULES } from '$lib/consts'
import {
BookOpen,
@@ -14,6 +14,7 @@
Github,
HelpCircle,
Home,
LogOut,
Play,
ServerCog,
Settings,
@@ -24,6 +25,11 @@
import { MenuItem } from '@rgossiaux/svelte-headlessui'
import UserMenu from './UserMenu.svelte'
import DiscordIcon from '../icons/brands/Discord.svelte'
import { WorkspaceService } from '$lib/gen'
import { sendUserToast } from '$lib/toast'
import { clearStores } from '$lib/storeUtils'
import { goto } from '$app/navigation'
import ConfirmationModal from '../common/confirmationModal/ConfirmationModal.svelte'
$: mainMenuLinks = [
{ label: 'Home', href: '/', icon: Home },
@@ -38,6 +44,13 @@
}
]
async function leaveWorkspace() {
await WorkspaceService.leaveWorkspace({ workspace: $workspaceStore ?? '' })
sendUserToast('You left the workspace')
clearStores()
goto('/user/workspaces')
}
$: secondaryMenuLinks = [
// {
// label: 'Workspace',
@@ -74,6 +87,19 @@
faIcon: undefined
}
]
: []),
...(!$superadmin && !$userStore?.is_admin
? [
{
label: 'Leave Workspace',
action: () => {
leaveWorkspaceModal = true
},
class: 'text-red-400',
icon: LogOut,
faIcon: undefined
}
]
: [])
],
disabled: $userStore?.operator
@@ -124,6 +150,8 @@
]
export let isCollapsed: boolean = false
let leaveWorkspaceModal = false
</script>
<nav
@@ -146,20 +174,35 @@
{#each menuLink.subItems as subItem (subItem.href ?? subItem.label)}
<MenuItem>
<div class="py-1" role="none">
<a
href={subItem.href}
class="text-secondary block px-4 py-2 text-2xs hover:bg-surface-hover hover:text-primary"
role="menuitem"
tabindex="-1"
>
<div class="flex flex-row items-center gap-2">
{#if subItem.icon}
<svelte:component this={subItem.icon} size={16} />
{/if}
{#if subItem?.['action']}
<button
class="{subItem['class']} px-4 py-2 !text-2xs"
on:click={subItem?.['action']}
>
<div class="flex flex-row items-center gap-2">
{#if subItem.icon}
<svelte:component this={subItem.icon} size={16} />
{/if}
{subItem.label}
</div>
</a>
{subItem.label}
</div>
</button>
{:else}
<a
href={subItem.href}
class="text-secondary block px-4 py-2 text-2xs hover:bg-surface-hover hover:text-primary"
role="menuitem"
tabindex="-1"
>
<div class="flex flex-row items-center gap-2">
{#if subItem.icon}
<svelte:component this={subItem.icon} size={16} />
{/if}
{subItem.label}
</div>
</a>
{/if}
</div>
</MenuItem>
{/each}
@@ -203,3 +246,19 @@
</div>
</div>
</nav>
<ConfirmationModal
open={leaveWorkspaceModal}
title="Leave workspace"
confirmationText="Remove"
on:canceled={() => {
leaveWorkspaceModal = false
}}
on:confirmed={() => {
leaveWorkspace()
}}
>
<div class="flex flex-col w-full space-y-4">
<span>Are you sure you want to leave this workspace?</span>
</div>
</ConfirmationModal>
@@ -1,5 +1,5 @@
<script lang="ts">
import { userWorkspaces, workspaceStore } from '$lib/stores'
import { superadmin, userStore, userWorkspaces, workspaceStore } from '$lib/stores'
import { Building, Plus, Settings } from 'lucide-svelte'
import Menu from '../common/menu/MenuV2.svelte'
@@ -87,19 +87,21 @@
All workspaces & invites
</a>
</div>
<div class="py-1" role="none">
<MenuItem>
<a
href="/workspace_settings"
class="text-secondary px-4 py-2 text-xs hover:bg-surface-hover hover:text-primary flex flex-flow gap-2"
role="menuitem"
tabindex="-1"
>
<Settings size={16} />
Workspace Settings
</a>
</MenuItem>
</div>
{#if $userStore?.is_admin || $superadmin}
<div class="py-1" role="none">
<MenuItem>
<a
href="/workspace_settings"
class="text-secondary px-4 py-2 text-xs hover:bg-surface-hover hover:text-primary flex flex-flow gap-2"
role="menuitem"
tabindex="-1"
>
<Settings size={16} />
Workspace Settings
</a>
</MenuItem>
</div>
{/if}
</div>
{#if $enterpriseLicense}
<MultiplayerMenu />