Skip to content

Commit

Permalink
Auth Token Delete
Browse files Browse the repository at this point in the history
  • Loading branch information
wyatt-herkamp committed Aug 28, 2024
1 parent 48b066e commit 6a1f851
Show file tree
Hide file tree
Showing 7 changed files with 86 additions and 60 deletions.
20 changes: 20 additions & 0 deletions crates/core/src/database/user/auth_token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,26 @@ impl AuthToken {
};
Ok(actions.contains(&repository_action))
}
pub async fn get_by_id_and_user_id(
id: i32,
user_id: i32,
database: &PgPool,
) -> sqlx::Result<Option<Self>> {
let token =
sqlx::query_as(r#"SELECT * FROM user_auth_tokens WHERE id = $1 AND user_id = $2"#)
.bind(id)
.bind(user_id)
.fetch_optional(database)
.await?;
Ok(token)
}
pub async fn delete(&self, database: &PgPool) -> sqlx::Result<()> {
sqlx::query(r#"DELETE FROM user_auth_tokens WHERE id = $1"#)
.bind(self.id)
.execute(database)
.await?;
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct NewAuthToken {
Expand Down
35 changes: 33 additions & 2 deletions nitro_repo/src/app/api/user/tokens.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
use axum::{
body::Body,
extract::{Path, State},
response::Response,
routing::{get, post},
routing::{delete, get, post},
Json,
};
use axum_extra::{headers::UserAgent, TypedHeader};
use http::StatusCode;
use nr_core::{
database::user::{auth_token::NewAuthToken, UserType},
database::user::{
auth_token::{AuthToken, NewAuthToken},
UserType,
},
user::{permissions::RepositoryActions, scopes::NRScope, token::AuthTokenFullResponse},
};
use serde::{Deserialize, Serialize};
Expand All @@ -27,6 +31,7 @@ pub fn token_routes() -> axum::Router<NitroRepo> {
.route("/create", post(create))
.route("/list", get(list))
.route("/get/:id", get(get_token))
.route("/delete/:id", delete(delete_token))
}

#[derive(Debug, Serialize, Deserialize, ToSchema)]
Expand Down Expand Up @@ -129,3 +134,29 @@ async fn get_token(
.status(StatusCode::OK)
.json_body(&tokens)
}
#[utoipa::path(
delete,
path = "/token/delete/{id}",
responses(
(status = 200, description = "Token Deleted"),
),
)]
#[instrument]
async fn delete_token(
auth: OnlySessionAllowedAuthentication,
Path(id): Path<i32>,
State(site): State<NitroRepo>,
) -> Result<Response, InternalError> {
let Some(token) = AuthToken::get_by_id_and_user_id(id, auth.get_id(), site.as_ref()).await?
else {
return Ok(Response::builder()
.status(StatusCode::NOT_FOUND)
.body(Body::empty())
.unwrap());
};
token.delete(site.as_ref()).await?;
Ok(Response::builder()
.status(StatusCode::NO_CONTENT)
.body(Body::empty())
.unwrap())
}
1 change: 0 additions & 1 deletion nitro_repo/src/repository/npm/login/couch_db.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use std::fmt::Debug;

use chrono::{DateTime, FixedOffset};
use derive_more::derive::From;
use nr_core::{
database::user::auth_token::NewRepositoryToken, user::permissions::RepositoryActions,
Expand Down
23 changes: 1 addition & 22 deletions site/src/components/nav/sideNav/SideNav.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,28 +16,7 @@ nav {
flex-direction: column;
gap: 0.5rem;
}
.navLink {
text-decoration: none;
color: $text;
font-weight: bold;
padding: 0.5rem;
// Align text vertically
display: flex;
align-items: center;
gap: 0.5rem;
// Box
border-radius: 0.5rem;
&:hover {
background-color: $primary-70;
transition: background-color 0.3s ease;
}
}
.navLink[data-active='true'] {
background-color: $primary-70;
&:hover {
cursor: default;
}
}
#logoAndHome {
img {
width: 2rem;
Expand Down
44 changes: 17 additions & 27 deletions site/src/components/repository/RepositoryToActionList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -19,33 +19,26 @@
<BaseSwitch v-model="entry.actions.can_edit" />
</div>
<div class="col">
<button
type="button"
class="actionButton"
@click="removeRepositoryScopeEntry(entry.repositoryId)">
<button type="button" class="actionButton" @click="removeEntry(entry.repositoryId)">
Remove
</button>
</div>
</div>
<div class="row item" id="create">
<div class="col" id="repoDropDown">
<RepositoryDropdown v-model="newRepositoryScopeEntry.repositoryId" />
<RepositoryDropdown v-model="newEntry.repositoryId" />
</div>
<div class="col">
<BaseSwitch v-model="newRepositoryScopeEntry.actions.can_read" />
<BaseSwitch v-model="newEntry.actions.can_read" />
</div>
<div class="col">
<BaseSwitch v-model="newRepositoryScopeEntry.actions.can_write" />
<BaseSwitch v-model="newEntry.actions.can_write" />
</div>
<div class="col">
<BaseSwitch v-model="newRepositoryScopeEntry.actions.can_edit" />
<BaseSwitch v-model="newEntry.actions.can_edit" />
</div>
<div class="col">
<button
type="button"
class="actionButton"
@click="addRepositoryScopeEntry"
:disabled="!isNewEntryValid">
<button type="button" class="actionButton" @click="addEntry" :disabled="!isNewEntryValid">
Add
</button>
</div>
Expand All @@ -69,51 +62,48 @@ function getRepositoryName(repositoryId: string) {
const repositoryEntries = defineModel<Array<NewAuthTokenRepositoryScope>>({
required: true
})
const newRepositoryScopeEntry = ref<NewAuthTokenRepositoryScope>({
const newEntry = ref<NewAuthTokenRepositoryScope>({
repositoryId: '',
actions: new RepositoryActionsType([])
})
const isNewEntryValid = computed(() => {
if (
!newRepositoryScopeEntry.value.repositoryId ||
newRepositoryScopeEntry.value.repositoryId == ''
) {
if (!newEntry.value.repositoryId || newEntry.value.repositoryId == '') {
return false
}
if (newRepositoryScopeEntry.value.actions.asArray().length === 0) {
if (newEntry.value.actions.asArray().length === 0) {
return false
}
return true
})
function addRepositoryScopeEntry() {
function addEntry() {
for (const repository of repositoryEntries.value) {
if (repository.repositoryId === newRepositoryScopeEntry.value.repositoryId) {
repository.actions = newRepositoryScopeEntry.value.actions
if (repository.repositoryId === newEntry.value.repositoryId) {
repository.actions = newEntry.value.actions
notify({
type: 'success',
title: 'Repository Already Exists',
text: 'Values have been updated.'
})
newRepositoryScopeEntry.value = {
newEntry.value = {
repositoryId: '',
actions: new RepositoryActionsType([])
}
return
}
}
repositoryEntries.value.push({
repositoryId: newRepositoryScopeEntry.value.repositoryId,
actions: newRepositoryScopeEntry.value.actions
repositoryId: newEntry.value.repositoryId,
actions: newEntry.value.actions
})
newRepositoryScopeEntry.value = {
newEntry.value = {
repositoryId: '',
actions: new RepositoryActionsType([])
}
}
function removeRepositoryScopeEntry(id: string) {
function removeEntry(id: string) {
repositoryEntries.value = repositoryEntries.value.filter((entry) => entry.repositoryId !== id)
}
</script>
Expand Down
1 change: 1 addition & 0 deletions site/src/router/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ declare module 'vue-router' {
requiresRepositoryManager?: boolean
requiresUserManager?: boolean
sideBar?: Component
tag?: string
}
}
const router = createRouter({
Expand Down
22 changes: 14 additions & 8 deletions site/src/views/profile/ProfileTokens.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,28 +9,23 @@
:data-expanded="expandedToken == token.token.id"
@click="tokenClicked(token.token.id)">
<div class="tokenElementLine">
<KeyAndValue label="Source" :value="token.token.name || 'No name'" />
<KeyAndValue label="Name" :value="token.token.name || 'No name'" />

<KeyAndValue label="Source" :value="token.token.source" />
<KeyAndValue
label="Created On"
:value="new Date(token.token.created_at).toLocaleDateString()" />
</div>
<div v-if="expandedToken == token.token.id">
<div>
<h2>Repository Scopes</h2>
</div>
<div>
<h2>Scopes</h2>
</div>
<button>Delete</button>
<SubmitButton @click="deleteToken(token.token.id)">Delete</SubmitButton>
</div>
</li>
</ul>
</main>
</template>
<script setup lang="ts">
import KeyAndValue from '@/components/form/KeyAndValue.vue'
import SubmitButton from '@/components/form/SubmitButton.vue'
import http from '@/http'
import { sessionStore } from '@/stores/session'
import { type RawAuthTokenFullResponse } from '@/types/user/token'
Expand All @@ -47,6 +42,16 @@ function tokenClicked(tokenId: number) {
expandedToken.value = tokenId
}
}
async function deleteToken(id: number) {
await http
.delete(`/api/user/token/delete/${id}`)
.then(() => {
getAuthTokens()
})
.catch((error) => {
console.log(error)
})
}
async function getAuthTokens() {
if (user == undefined) {
return
Expand Down Expand Up @@ -76,6 +81,7 @@ main {
}
.tokenElement {
border: 1px solid #000;
}
.tokenElementLine {
display: grid;
Expand Down

0 comments on commit 6a1f851

Please sign in to comment.