feat: add username availability check API endpoint
feat: create user image retrieval API endpoint feat: enhance coin page with dynamic data fetching and improved UI feat: implement coin creation form with validation and submission logic feat: add user settings page with profile update functionality
This commit is contained in:
parent
9aa4ba157b
commit
16ad425bb5
48 changed files with 3030 additions and 326 deletions
|
|
@ -17,6 +17,8 @@ export const user = pgTable("user", {
|
|||
precision: 19,
|
||||
scale: 4,
|
||||
}).notNull().default("10000.0000"), // 10,000 *BUSS
|
||||
bio: varchar("bio", { length: 160 }).default("Hello am 48 year old man from somalia. Sorry for my bed england. I selled my wife for internet connection for play “conter stirk”"),
|
||||
username: varchar("username", { length: 30 }).notNull().unique(),
|
||||
});
|
||||
|
||||
export const session = pgTable("session", {
|
||||
|
|
@ -59,6 +61,7 @@ export const coin = pgTable("coin", {
|
|||
id: serial("id").primaryKey(),
|
||||
name: varchar("name", { length: 255 }).notNull(),
|
||||
symbol: varchar("symbol", { length: 10 }).notNull().unique(),
|
||||
icon: text("icon"), // New field for coin icon
|
||||
creatorId: integer("creator_id").references(() => user.id, { onDelete: "set null", }), // Coin can exist even if creator is deleted
|
||||
initialSupply: decimal("initial_supply", { precision: 28, scale: 8 }).notNull(),
|
||||
circulatingSupply: decimal("circulating_supply", { precision: 28, scale: 8 }).notNull(),
|
||||
|
|
|
|||
95
website/src/lib/server/s3.ts
Normal file
95
website/src/lib/server/s3.ts
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
import { S3Client, GetObjectCommand, PutObjectCommand, DeleteObjectCommand } from '@aws-sdk/client-s3';
|
||||
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
|
||||
import { PRIVATE_B2_KEY_ID, PRIVATE_B2_APP_KEY } from '$env/static/private';
|
||||
import { PUBLIC_B2_BUCKET, PUBLIC_B2_ENDPOINT, PUBLIC_B2_REGION } from '$env/static/public';
|
||||
|
||||
const s3Client = new S3Client({
|
||||
endpoint: PUBLIC_B2_ENDPOINT,
|
||||
region: PUBLIC_B2_REGION,
|
||||
credentials: {
|
||||
accessKeyId: PRIVATE_B2_KEY_ID,
|
||||
secretAccessKey: PRIVATE_B2_APP_KEY
|
||||
},
|
||||
forcePathStyle: true,
|
||||
requestChecksumCalculation: 'WHEN_REQUIRED',
|
||||
responseChecksumValidation: 'WHEN_REQUIRED',
|
||||
});
|
||||
|
||||
export async function generatePresignedUrl(key: string, contentType: string): Promise<string> {
|
||||
const command = new PutObjectCommand({
|
||||
Bucket: PUBLIC_B2_BUCKET,
|
||||
Key: key,
|
||||
ContentType: contentType
|
||||
});
|
||||
|
||||
return getSignedUrl(s3Client, command, { expiresIn: 3600 }); // 1 hour
|
||||
}
|
||||
|
||||
export async function deleteObject(key: string): Promise<void> {
|
||||
const command = new DeleteObjectCommand({
|
||||
Bucket: PUBLIC_B2_BUCKET,
|
||||
Key: key
|
||||
});
|
||||
|
||||
await s3Client.send(command);
|
||||
}
|
||||
|
||||
export async function generateDownloadUrl(key: string): Promise<string> {
|
||||
const command = new GetObjectCommand({
|
||||
Bucket: PUBLIC_B2_BUCKET,
|
||||
Key: key
|
||||
});
|
||||
|
||||
return getSignedUrl(s3Client, command, { expiresIn: 3600 });
|
||||
}
|
||||
|
||||
export async function uploadProfilePicture(
|
||||
identifier: string, // Can be user ID or a unique ID from social provider
|
||||
body: Uint8Array,
|
||||
contentType: string,
|
||||
contentLength?: number
|
||||
): Promise<string> {
|
||||
let fileExtension = contentType.split('/')[1];
|
||||
// Ensure a valid image extension or default to jpg
|
||||
if (!fileExtension || !['jpg', 'jpeg', 'png', 'gif', 'webp'].includes(fileExtension.toLowerCase())) {
|
||||
fileExtension = 'jpg';
|
||||
}
|
||||
const key = `avatars/${identifier}.${fileExtension}`;
|
||||
|
||||
const command = new PutObjectCommand({
|
||||
Bucket: PUBLIC_B2_BUCKET,
|
||||
Key: key,
|
||||
Body: body,
|
||||
ContentType: contentType,
|
||||
...(contentLength && { ContentLength: contentLength }),
|
||||
});
|
||||
|
||||
await s3Client.send(command);
|
||||
return key;
|
||||
}
|
||||
|
||||
export async function uploadCoinIcon(
|
||||
coinSymbol: string,
|
||||
body: Uint8Array,
|
||||
contentType: string,
|
||||
contentLength?: number
|
||||
): Promise<string> {
|
||||
let fileExtension = contentType.split('/')[1];
|
||||
if (!fileExtension || !['jpg', 'jpeg', 'png', 'gif', 'webp'].includes(fileExtension.toLowerCase())) {
|
||||
fileExtension = 'png';
|
||||
}
|
||||
const key = `coins/${coinSymbol.toLowerCase()}.${fileExtension}`;
|
||||
|
||||
const command = new PutObjectCommand({
|
||||
Bucket: PUBLIC_B2_BUCKET,
|
||||
Key: key,
|
||||
Body: body,
|
||||
ContentType: contentType,
|
||||
...(contentLength && { ContentLength: contentLength }),
|
||||
});
|
||||
|
||||
await s3Client.send(command);
|
||||
return key;
|
||||
}
|
||||
|
||||
export { s3Client };
|
||||
Reference in a new issue