263 lines
8.6 KiB
Markdown
263 lines
8.6 KiB
Markdown
---
|
|
title: User API
|
|
tags: [api, user, reference]
|
|
---
|
|
|
|
# User API
|
|
|
|
Two routers are mounted for users:
|
|
|
|
- `/api/user/*` - the new controller pattern in [`backend/src/services/user/userControllerRoutes.ts`](../../backend/src/services/user/userControllerRoutes.ts) wired to `userController`.
|
|
- `/api/users/*` - the legacy router in [`backend/src/services/user/userRoutes.ts`](../../backend/src/services/user/userRoutes.ts) (kept for backward compatibility, primarily used by the admin console).
|
|
|
|
Address-book CRUD lives on its own service: [`/api/addresses/*`](../../backend/src/services/address/addressRoutes.ts). All endpoints require `Bearer JWT` unless noted. Source of truth model: [[User]].
|
|
|
|
## Profile (current user)
|
|
|
|
### GET /api/user/profile
|
|
|
|
**Description:** Returns the caller's profile.
|
|
**Auth required:** Bearer JWT
|
|
**Response 200:**
|
|
```json
|
|
{ "success": true, "data": { /* User without password / verification tokens */ } }
|
|
```
|
|
**Source:** `userController.getCurrentUserProfile`
|
|
|
|
### PUT /api/user/profile
|
|
|
|
**Description:** Updates the caller's profile.
|
|
**Auth required:** Bearer JWT
|
|
**Request body (whitelisted fields):**
|
|
```ts
|
|
{
|
|
firstName?: string;
|
|
lastName?: string;
|
|
name?: string; // alias for profile.name
|
|
phone?: string;
|
|
bio?: string;
|
|
website?: string;
|
|
photoURL?: string; // also mirrored to profile.avatar
|
|
isPublic?: boolean;
|
|
address?: {
|
|
street?: string;
|
|
city?: string;
|
|
state?: string;
|
|
country?: string;
|
|
postalCode?: string;
|
|
};
|
|
preferences?: {
|
|
language?: "en" | "fa" | "ar";
|
|
currency?: "USD" | "EUR" | "IRR" | "AED";
|
|
notifications?: { email?: boolean; sms?: boolean; push?: boolean };
|
|
};
|
|
}
|
|
```
|
|
**Response 200:** Updated user.
|
|
|
|
### GET /api/users/profile
|
|
|
|
**Description:** Legacy equivalent of the above. Returns the full sanitized user document.
|
|
**Auth required:** Bearer JWT
|
|
|
|
### GET /api/users/profile/:userId
|
|
|
|
**Description:** Public profile by id. If `profile.isPublic === false` and caller is not the owner or admin, only `firstName`, `lastName`, `avatar`, `role` are returned.
|
|
**Auth required:** Bearer JWT
|
|
|
|
## Avatar upload
|
|
|
|
Avatar upload is handled by the [[File API]]:
|
|
|
|
`POST /api/files/upload/avatar` (multipart `avatar`) returns a URL that the caller then writes to `profile.avatar` via `PUT /api/user/profile`.
|
|
|
|
## Wallet address
|
|
|
|
### GET /api/user/wallet-address
|
|
|
|
**Description:** Returns the caller's stored EVM wallet address (or `null`).
|
|
**Auth required:** Bearer JWT
|
|
**Response 200:** `{ "success": true, "data": { "walletAddress": "0x..." | null } }`
|
|
|
|
### PATCH /api/user/wallet-address
|
|
|
|
**Description:** Verifies an EIP-191 signed message and stores `profile.walletAddress`. The server uses `ethers.verifyMessage(message, signature)` and rejects if the recovered address does not match.
|
|
**Auth required:** Bearer JWT
|
|
**Request body:**
|
|
```ts
|
|
{
|
|
walletAddress: string; // 0x-prefixed 40-hex
|
|
signature: string; // signed `message`
|
|
message: string; // human-readable challenge text
|
|
}
|
|
```
|
|
**Response 200:** `{ "success": true, "data": { "walletAddress": "0x..." } }`
|
|
**Errors:**
|
|
- `400` missing fields, malformed address, signature mismatch
|
|
- `404` user not found
|
|
|
|
The legacy alias `PATCH /api/users/wallet-address` performs the same logic.
|
|
|
|
## Contacts and search
|
|
|
|
### GET /api/users/contacts
|
|
|
|
**Description:** Returns the users the caller is allowed to chat with based on role:
|
|
- `buyer` → sees `seller` + `admin`
|
|
- `seller` → sees `buyer` + `admin`
|
|
- `admin` → sees everyone
|
|
**Auth required:** Bearer JWT
|
|
**Response 200:** `{ "success": true, "data": { "contacts": [...], "count": N } }`
|
|
|
|
### GET /api/users/search?q=<term>&role=<role>
|
|
|
|
**Description:** Case-insensitive search across `firstName`/`lastName`/`email`. Returns up to 20 active users.
|
|
**Auth required:** Bearer JWT
|
|
**Errors:** `400` if `q.length < 2`.
|
|
|
|
### GET /api/users?role=...&isActive=true&search=...&page=1&limit=50
|
|
|
|
**Description:** Paginated user directory (legacy, no admin gate). See pagination conventions in [[API Overview]].
|
|
**Auth required:** Bearer JWT
|
|
|
|
## Admin: user management
|
|
|
|
These are duplicated across the two routers. The newer controller variants live under `/api/user/admin/*`; the legacy bodies live under `/api/users/admin/*`. All require `req.user.role === 'admin'` (the legacy routes check inline; the controller routes only check `authenticateToken` and the controller enforces the role).
|
|
|
|
### POST /api/user/admin/create
|
|
|
|
**Description:** Admin creates a user with a chosen role and verification state.
|
|
**Auth required:** Bearer JWT (admin)
|
|
**Request body:**
|
|
```ts
|
|
{
|
|
email: string;
|
|
password: string;
|
|
firstName: string;
|
|
lastName: string;
|
|
role?: "buyer" | "seller" | "admin"; // default "buyer"
|
|
isActive?: boolean; // default true
|
|
isVerified?: boolean; // default false
|
|
profile?: { /* free-form */ };
|
|
}
|
|
```
|
|
**Response 201:** `{ success, data: { user } }`
|
|
**Errors:** `400` missing fields, `403` non-admin, `409` email exists.
|
|
|
|
### DELETE /api/user/admin/:userId
|
|
|
|
**Description:** Hard-delete a user. Prevents self-deletion and deleting other admins.
|
|
**Auth required:** Bearer JWT (admin)
|
|
**Response 200:** `{ success, data: { deletedUserId } }`
|
|
**Errors:** `400` self-delete, `403` admin-on-admin, `404` not found.
|
|
|
|
### PATCH /api/user/admin/:userId/status
|
|
|
|
**Description:** Activate / suspend a user.
|
|
**Auth required:** Bearer JWT (admin)
|
|
**Request body:** `{ isActive: boolean; reason?: string }`
|
|
**Response 200:** `{ success, data: { user: { _id, isActive, statusUpdatedAt } } }`
|
|
|
|
### PATCH /api/user/admin/:userId/toggle-status
|
|
|
|
**Description:** Flip active/suspended without explicit body.
|
|
**Auth required:** Bearer JWT (admin)
|
|
|
|
### PATCH /api/user/admin/:userId/role
|
|
|
|
**Description:** Change a user's role.
|
|
**Auth required:** Bearer JWT (admin)
|
|
**Request body:** `{ role: "buyer" | "seller" | "admin"; reason?: string }`
|
|
**Errors:** `400` invalid role.
|
|
|
|
### GET /api/user/admin/list
|
|
|
|
**Description:** Paginated admin user list with filters.
|
|
**Auth required:** Bearer JWT (admin)
|
|
**Query params:** `role`, `isActive`, `isVerified`, `search`, `page`, `limit`, `sortBy`, `sortOrder`
|
|
**Response 200:** `{ success, data: { users, pagination, stats: { totalUsers, activeUsers, verifiedUsers, buyers, sellers, admins } } }`
|
|
|
|
### GET /api/user/admin/:userId/dependencies
|
|
|
|
**Description:** Returns a count of related entities (purchase requests, offers, payments) before a destructive admin operation.
|
|
**Auth required:** Bearer JWT (admin)
|
|
|
|
### GET /api/users/admin/stats
|
|
|
|
**Description:** Aggregated user stats — total/active/verified counts, role distribution, activity buckets (24h / 7d / 30d).
|
|
**Auth required:** Bearer JWT (admin)
|
|
|
|
### GET /api/users/admin/:userId
|
|
|
|
**Description:** Fetch a single user by id (admin view, includes preferences and last-login).
|
|
**Auth required:** Bearer JWT (admin)
|
|
|
|
### PUT /api/users/admin/:userId
|
|
|
|
**Description:** Mass update a user document (admin override).
|
|
**Auth required:** Bearer JWT (admin)
|
|
|
|
### PUT /api/users/admin/update/:email
|
|
|
|
**Description:** Same as above but keyed on email.
|
|
**Auth required:** Bearer JWT (admin)
|
|
|
|
### PATCH /api/users/admin/:userId/password
|
|
|
|
**Description:** Admin forces a new password. Wipes `refreshTokens` so all sessions are invalidated.
|
|
**Auth required:** Bearer JWT (admin)
|
|
**Request body:** `{ newPassword: string; reason?: string }`
|
|
|
|
### POST /api/users/admin/:userId/resend-verification
|
|
|
|
**Description:** Regenerate the 8-digit email verification code and re-send the verification email.
|
|
**Auth required:** Bearer JWT (admin)
|
|
**Errors:** `400` user already verified.
|
|
|
|
## Address book
|
|
|
|
Source: [`backend/src/services/address/addressRoutes.ts`](../../backend/src/services/address/addressRoutes.ts), model: [[Address]].
|
|
|
|
### GET /api/addresses
|
|
|
|
**Description:** List the caller's addresses.
|
|
**Auth required:** Bearer JWT
|
|
**Response 200:** `{ success: true, data: [Address, ...] }`
|
|
|
|
### POST /api/addresses
|
|
|
|
**Description:** Create a new address. First address auto-becomes primary.
|
|
**Auth required:** Bearer JWT
|
|
**Request body:**
|
|
```ts
|
|
{
|
|
fullName: string;
|
|
phone: string;
|
|
street: string;
|
|
city: string;
|
|
state?: string;
|
|
country: string;
|
|
postalCode?: string;
|
|
isPrimary?: boolean;
|
|
notes?: string;
|
|
}
|
|
```
|
|
|
|
### PUT /api/addresses/:addressId
|
|
|
|
**Description:** Update an address.
|
|
**Auth required:** Bearer JWT
|
|
**Errors:** `404` not owned by user.
|
|
|
|
### DELETE /api/addresses/:addressId
|
|
|
|
**Description:** Delete an address. If it was the primary, another address is promoted.
|
|
**Auth required:** Bearer JWT
|
|
|
|
### PATCH /api/addresses/:addressId/primary
|
|
|
|
**Description:** Promote an address to primary; demotes the previous primary.
|
|
**Auth required:** Bearer JWT
|
|
|
|
See [[Address]] for the schema, and [[Marketplace API]] for how purchase requests reference an address.
|