Skip to content

Commit

Permalink
Allow admins to view user email (#3261)
Browse files Browse the repository at this point in the history
  • Loading branch information
Geometrically authored Feb 14, 2025
1 parent d9983de commit 975427b
Show file tree
Hide file tree
Showing 3 changed files with 140 additions and 0 deletions.
61 changes: 61 additions & 0 deletions apps/frontend/src/pages/admin/user_email.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<template>
<div class="normal-page no-sidebar">
<h1>User account request</h1>
<div class="normal-page__content">
<div class="card flex flex-col gap-3">
<div class="flex flex-col gap-2">
<label for="name">
<span class="text-lg font-semibold text-contrast">
User email
<span class="text-brand-red">*</span>
</span>
</label>
<input
id="name"
v-model="userEmail"
type="email"
maxlength="64"
:placeholder="`Enter user email...`"
autocomplete="off"
/>
</div>
<div class="flex gap-2">
<ButtonStyled color="brand">
<button @click="getUserFromEmail">
<MailIcon aria-hidden="true" />
Get user account
</button>
</ButtonStyled>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ButtonStyled } from "@modrinth/ui";
import { MailIcon } from "@modrinth/assets";
const userEmail = ref("");
async function getUserFromEmail() {
startLoading();
try {
const result = await useBaseFetch(`user_email?email=${encodeURIComponent(userEmail.value)}`, {
method: "GET",
apiVersion: 3,
});
await navigateTo(`/user/${result.username}`);
} catch (err) {
console.error(err);
addNotification({
group: "main",
title: "An error occurred",
text: err.data.description,
type: "error",
});
}
stopLoading();
}
</script>

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

57 changes: 57 additions & 0 deletions apps/labrinth/src/routes/v3/users.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ use crate::{
pub fn config(cfg: &mut web::ServiceConfig) {
cfg.route("user", web::get().to(user_auth_get));
cfg.route("users", web::get().to(users_get));
cfg.route("user_email", web::get().to(admin_user_email));

cfg.service(
web::scope("user")
Expand All @@ -44,6 +45,62 @@ pub fn config(cfg: &mut web::ServiceConfig) {
);
}

#[derive(Deserialize)]
pub struct UserEmailQuery {
pub email: String,
}

pub async fn admin_user_email(
req: HttpRequest,
pool: web::Data<PgPool>,
redis: web::Data<RedisPool>,
session_queue: web::Data<AuthQueue>,
email: web::Query<UserEmailQuery>,
) -> Result<HttpResponse, ApiError> {
let user = get_user_from_headers(
&req,
&**pool,
&redis,
&session_queue,
Some(&[Scopes::SESSION_ACCESS]),
)
.await
.map(|x| x.1)?;

if !user.role.is_admin() {
return Err(ApiError::CustomAuthentication(
"You do not have permission to get a user from their email!"
.to_string(),
));
}

let user_id = sqlx::query!(
"
SELECT id FROM users
WHERE LOWER(email) = LOWER($1)
",
email.email
)
.fetch_optional(&**pool)
.await?
.map(|x| x.id)
.ok_or_else(|| {
ApiError::InvalidInput(
"The email provided is not associated with a user!".to_string(),
)
})?;

let user =
User::get_id(crate::database::models::UserId(user_id), &**pool, &redis)
.await?;

if let Some(user) = user {
Ok(HttpResponse::Ok().json(user))
} else {
Err(ApiError::NotFound)
}
}

pub async fn projects_list(
req: HttpRequest,
info: web::Path<(String,)>,
Expand Down

0 comments on commit 975427b

Please sign in to comment.