mirror of
https://github.com/versia-pub/server.git
synced 2025-12-06 08:28:19 +01:00
feat(api): ✨ Add new endpoint to get a user by its username
This commit is contained in:
parent
407eb5e205
commit
be881f18cd
|
|
@ -16,6 +16,7 @@ Lysand Server `0.7.0` is backwards compatible with `0.6.0`. However, some new fe
|
|||
- Added [**TOS and Privacy Policy**](docs/api/mastodon.md) endpoints.
|
||||
- Added [**Challenge API**](docs/api/challenges.md). (basically CAPTCHAS). This can be enabled/disabled by administrators. No `lysand-fe` support yet.
|
||||
- Added ability to change the `username` of a user. ([Mastodon API extension](docs/api/mastodon.md)).
|
||||
- Added an endpoint to get a user by its username.
|
||||
- Add OpenID Connect registration support. Admins can now disable username/password registration entirely and still allow users to sign up via OpenID Connect.
|
||||
- Add option to never convert vector images to a raster format.
|
||||
- Refactor logging system to be more robust and easier to use. Logfiles are now automatically rotated.
|
||||
|
|
|
|||
|
|
@ -219,3 +219,21 @@ This request is authenticated with the user's Mastodon API access token.
|
|||
}
|
||||
```
|
||||
|
||||
## Get User By Username
|
||||
|
||||
Gets a user by their username.
|
||||
|
||||
```http
|
||||
GET /api/v1/users/id?username=myCoolUser
|
||||
```
|
||||
|
||||
### Response
|
||||
|
||||
Returns an account object.
|
||||
|
||||
```ts
|
||||
// 200 OK
|
||||
{
|
||||
id: string;
|
||||
// Account object
|
||||
}
|
||||
|
|
@ -50,12 +50,13 @@ Contains the same extensions as `/api/v1/instance`, except `banner` which uses t
|
|||
|
||||
(`/api/v1/accounts/:id`, `/api/v1/accounts/verify_credentials`, ...)
|
||||
|
||||
An extra attribute has been adding to all returned account objects:
|
||||
Two extra attributes has been adding to all returned account objects:
|
||||
|
||||
```ts
|
||||
{
|
||||
// ...
|
||||
roles: LysandRoles[];
|
||||
uri: string;
|
||||
}
|
||||
```
|
||||
|
||||
|
|
@ -63,7 +64,11 @@ An extra attribute has been adding to all returned account objects:
|
|||
|
||||
An array of roles from [Lysand Roles](./roles.md).
|
||||
|
||||
### `/api/v1/accounts/update_credentials`
|
||||
### `uri`
|
||||
|
||||
The URI of the account's Lysand object (for federation). Similar to Mastodon's `uri` field on notes.
|
||||
|
||||
## `/api/v1/accounts/update_credentials`
|
||||
|
||||
The `username` parameter can now (optionally) be set to change the user's handle.
|
||||
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@
|
|||
"@inquirer/input": "^2.2.1",
|
||||
"@json2csv/plainjs": "^7.0.6",
|
||||
"@logtape/logtape": "npm:@jsr/logtape__logtape@0.4.2",
|
||||
"@lysand-org/client": "^0.2.3",
|
||||
"@lysand-org/client": "^0.2.4",
|
||||
"@lysand-org/federation": "^2.1.1",
|
||||
"@oclif/core": "^4.0.12",
|
||||
"@tufjs/canonical-json": "^2.0.0",
|
||||
|
|
|
|||
|
|
@ -636,6 +636,7 @@ export class User extends BaseInterface<typeof Users, UserWithRelations> {
|
|||
username: user.username,
|
||||
display_name: user.displayName,
|
||||
note: user.note,
|
||||
uri: this.getUri(),
|
||||
url:
|
||||
user.uri ||
|
||||
new URL(`/@${user.username}`, config.http.base_url).toString(),
|
||||
|
|
|
|||
|
|
@ -72,6 +72,7 @@ describe(meta.route, () => {
|
|||
statuses_count: 40,
|
||||
note: users[0].data.note,
|
||||
acct: users[0].data.username,
|
||||
uri: expect.any(String),
|
||||
url: expect.any(String),
|
||||
avatar_static: expect.any(String),
|
||||
header_static: expect.any(String),
|
||||
|
|
|
|||
44
server/api/api/v1/accounts/id/index.test.ts
Normal file
44
server/api/api/v1/accounts/id/index.test.ts
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
import { afterAll, describe, expect, test } from "bun:test";
|
||||
import type { Account as ApiAccount } from "@lysand-org/client/types";
|
||||
import { config } from "config-manager";
|
||||
import { getTestUsers, sendTestRequest } from "~/tests/utils";
|
||||
import { meta } from "./index";
|
||||
|
||||
const { users, deleteUsers } = await getTestUsers(5);
|
||||
|
||||
afterAll(async () => {
|
||||
await deleteUsers();
|
||||
});
|
||||
|
||||
// /api/v1/accounts/id
|
||||
describe(meta.route, () => {
|
||||
test("should correctly get user from username", async () => {
|
||||
const response = await sendTestRequest(
|
||||
new Request(
|
||||
new URL(
|
||||
`${meta.route}?username=${users[0].data.username}`,
|
||||
config.http.base_url,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
|
||||
const data = (await response.json()) as ApiAccount;
|
||||
|
||||
expect(data.id).toBe(users[0].id);
|
||||
});
|
||||
|
||||
test("should return 404 for non-existent user", async () => {
|
||||
const response = await sendTestRequest(
|
||||
new Request(
|
||||
new URL(
|
||||
`${meta.route}?username=${users[0].data.username}-nonexistent`,
|
||||
config.http.base_url,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(response.status).toBe(404);
|
||||
});
|
||||
});
|
||||
51
server/api/api/v1/accounts/id/index.ts
Normal file
51
server/api/api/v1/accounts/id/index.ts
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
import { applyConfig, auth, handleZodError } from "@/api";
|
||||
import { errorResponse, jsonResponse } from "@/response";
|
||||
import type { Hono } from "@hono/hono";
|
||||
import { zValidator } from "@hono/zod-validator";
|
||||
import { and, eq, isNull } from "drizzle-orm";
|
||||
import { z } from "zod";
|
||||
import { RolePermissions, Users } from "~/drizzle/schema";
|
||||
import { User } from "~/packages/database-interface/user";
|
||||
|
||||
export const meta = applyConfig({
|
||||
allowedMethods: ["GET"],
|
||||
ratelimits: {
|
||||
max: 30,
|
||||
duration: 60,
|
||||
},
|
||||
route: "/api/v1/accounts/id",
|
||||
auth: {
|
||||
required: false,
|
||||
oauthPermissions: [],
|
||||
},
|
||||
permissions: {
|
||||
required: [RolePermissions.Search],
|
||||
},
|
||||
});
|
||||
|
||||
export const schemas = {
|
||||
query: z.object({
|
||||
username: z.string().min(1).max(512),
|
||||
}),
|
||||
};
|
||||
|
||||
export default (app: Hono) =>
|
||||
app.on(
|
||||
meta.allowedMethods,
|
||||
meta.route,
|
||||
zValidator("query", schemas.query, handleZodError),
|
||||
auth(meta.auth, meta.permissions),
|
||||
async (context) => {
|
||||
const { username } = context.req.valid("query");
|
||||
|
||||
const user = await User.fromSql(
|
||||
and(eq(Users.username, username), isNull(Users.instanceId)),
|
||||
);
|
||||
|
||||
if (!user) {
|
||||
return errorResponse("User not found", 404);
|
||||
}
|
||||
|
||||
return jsonResponse(user.toApi());
|
||||
},
|
||||
);
|
||||
Loading…
Reference in a new issue