Skip to content

Commit

Permalink
Add avatar functionality for user profile
Browse files Browse the repository at this point in the history
  • Loading branch information
Zokhoi committed Sep 7, 2024
1 parent d730b25 commit 16acaf0
Show file tree
Hide file tree
Showing 13 changed files with 85 additions and 6 deletions.
18 changes: 13 additions & 5 deletions deepwell/src/endpoints/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ use crate::models::file::Model as FileModel;
use crate::models::file_revision::Model as FileRevisionModel;
use crate::services::blob::BlobService;
use crate::services::file::{
DeleteFile, DeleteFileOutput, EditFile, EditFileOutput, GetFileDetails,
GetFileOutput, MoveFile, MoveFileOutput, RestoreFile, RestoreFileOutput, UploadFile,
UploadFileOutput,
DeleteFile, DeleteFileOutput, EditFile, EditFileOutput, GetBlobOutput,
GetFileDetails, GetFileOutput, MoveFile, MoveFileOutput, RestoreFile,
RestoreFileOutput, UploadFile, UploadFileOutput,
};
use crate::services::Result;
use crate::web::{Bytes, FileDetails};
Expand All @@ -36,10 +36,18 @@ use crate::web::{Bytes, FileDetails};
pub async fn blob_get(
ctx: &ServiceContext<'_>,
params: Params<'static>,
) -> Result<Vec<u8>> {
) -> Result<GetBlobOutput> {
info!("Getting blob for S3 hash");
let hash: Bytes = params.parse()?;
BlobService::get(ctx, hash.as_ref()).await
let data = BlobService::get(ctx, hash.as_ref()).await?;
let metadata = BlobService::get_metadata(ctx, hash.as_ref()).await?;

let output = GetBlobOutput {
data,
mime: metadata.mime,
size: metadata.size,
};
Ok(output)
}

pub async fn file_get(
Expand Down
7 changes: 7 additions & 0 deletions deepwell/src/services/file/structs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,13 @@ pub struct GetFileOutput {
pub hidden_fields: Vec<String>,
}

#[derive(Serialize, Debug, Clone)]
pub struct GetBlobOutput {
pub data: Vec<u8>,
pub mime: String,
pub size: i64,
}

#[derive(Deserialize, Debug, Clone)]
pub struct EditFile {
pub site_id: i64,
Expand Down
13 changes: 13 additions & 0 deletions framerail/src/lib/server/deepwell/getFile.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { client } from "$lib/server/deepwell/index.ts"

export async function getFileByHash(
/** Either a Uint8Array or a hex string */
fileHash: Uint8Array | string
): Promise<Blob> {
let res = await client.request(
"blob_get",
typeof fileHash === "string" ? fileHash : Buffer.from(fileHash).toString("hex")
)

return new Blob([new Uint8Array(res.data)], { type: res.mime })
}
4 changes: 4 additions & 0 deletions framerail/src/lib/server/deepwell/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ export async function userEdit(
}
if (Array.isArray(params.locales) && params.locales.every((v) => typeof v === "string"))
data.locales = params.locales
if (params.avatar instanceof File && params.avatar.type.startsWith("image/")) {
let srcBuf = await params.avatar.arrayBuffer()
data.avatar = Buffer.from(srcBuf).toString("hex")
}

return client.request("user_edit", {
user: userId,
Expand Down
12 changes: 12 additions & 0 deletions framerail/src/lib/server/load/user.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import defaults from "$lib/defaults"
import { parseAcceptLangHeader } from "$lib/locales"
import { getFileByHash } from "$lib/server/deepwell/getFile"
import { translate } from "$lib/server/deepwell/translate"
import { userView } from "$lib/server/deepwell/user.ts"
import type { TranslateKeys } from "$lib/types"
Expand Down Expand Up @@ -55,6 +56,15 @@ export async function loadUser(username?: string, request, cookies) {
delete viewData.user[sensitiveKeys[i]]
}

// Get user avatar image
if (viewData.user.avatar_s3_hash !== null) {
let avatar = await getFileByHash(new Uint8Array(viewData.user.avatar_s3_hash))
let dataurl = `data:${avatar.type};base64,${Buffer.from(
await avatar.arrayBuffer()
).toString("base64")}`
viewData.user.avatar = dataurl
}

translateKeys = {
...translateKeys,

Expand All @@ -64,9 +74,11 @@ export async function loadUser(username?: string, request, cookies) {
"cancel": {},

// User profile attributes
"avatar": {},
"user-profile-info.name": {},
"user-profile-info.real-name": {},
"user-profile-info.email": {},
"user-profile-info.avatar": {},
"user-profile-info.gender": {},
"user-profile-info.birthday": {},
"user-profile-info.location": {},
Expand Down
5 changes: 5 additions & 0 deletions framerail/src/lib/sigma-esque/sigma-esque.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@
outline: 1px solid var(--error);
}
}
.user-attribute.avatar img {
max-width: 200px;
max-height: 200px;
}
}
.header {
Expand Down
11 changes: 11 additions & 0 deletions framerail/src/routes/[x+2d]/user/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
let showErrorPopup = useErrorPopup()
let isEdit = false
let avatarFiles: FileList
async function saveEdit() {
let form = document.getElementById("editor")
Expand Down Expand Up @@ -61,6 +62,16 @@
type="text"
value={$page.data.user.email}
/>
<label for="avatar"
>{$page.data.internationalization?.["user-profile-info.avatar"]}</label
>
<input
name="avatar"
class="user-attribute avatar"
accept="image/png,image/jpeg,image/bmp"
type="file"
bind:files={avatarFiles}
/>
<label for="gender"
>{$page.data.internationalization?.["user-profile-info.gender"]}</label
>
Expand Down
4 changes: 3 additions & 1 deletion framerail/src/routes/[x+2d]/user/+server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export async function POST(event) {
let biography = data.get("biography")?.toString().trim()
let userPage = data.get("user-page")?.toString().trim()
let locales = data.get("locales")?.toString().trim()
let avatar = data.get("avatar")?.valueOf()

let body: Record<string, any> = {
name,
Expand All @@ -27,7 +28,8 @@ export async function POST(event) {
location,
biography,
user_page: userPage,
locales: locales?.split(" ").filter((v) => v.trim())
locales: locales?.split(" ").filter((v) => v.trim()),
avatar
}

let res = await userEdit(session?.user_id, body)
Expand Down
13 changes: 13 additions & 0 deletions framerail/src/routes/[x+2d]/user/[slug]/page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,19 @@
</div>
{/if}

{#if $page.data.user.avatar}
<div class="user-attribute avatar">
<span class="user-attribute-label"
>{$page.data.internationalization?.["user-profile-info.avatar"]}</span
>
<img
class="user-attribute-value"
alt={$page.data.internationalization?.avatar}
src={$page.data.user.avatar}
/>
</div>
{/if}

{#if $page.data.user.birthday}
<div class="user-attribute birthday">
<span class="user-attribute-label"
Expand Down
1 change: 1 addition & 0 deletions locales/fluent/base/en.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ title = Title
upload = Upload
view = View
vote = Vote
avatar = Profile image
search = Search
.placeholder = Search...
Expand Down
1 change: 1 addition & 0 deletions locales/fluent/base/zh_Hans.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ title = 标题
upload = 上传
view = 检视
vote = 评分
avatar = 头像
search = 搜索
.placeholder = 搜索……
Expand Down
1 change: 1 addition & 0 deletions locales/fluent/user-profile/en.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ user-profile-info =
.name = Name:
.real-name = Real name:
.email = Email:
.avatar = Profile image:
.pronouns = Pronouns:
.birthday = Birthday:
.location = Location:
Expand Down
1 change: 1 addition & 0 deletions locales/fluent/user-profile/zh_Hans.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ user-profile-info =
.name = 姓名:
.real-name = 真实姓名:
.email = 电邮地址:
.avatar = 头像:
.pronouns = 性别代称:
.birthday = 生日:
.location = 定位:
Expand Down

0 comments on commit 16acaf0

Please sign in to comment.