feat: test comments, issues and mentions
This commit is contained in:
parent
506aaaf16d
commit
fa48c720b7
2 changed files with 143 additions and 23 deletions
|
@ -3,6 +3,9 @@ import authtoken from "../secrets/user1-accesstoken.json";
|
||||||
|
|
||||||
const token = authtoken["sha1"];
|
const token = authtoken["sha1"];
|
||||||
const username = authtoken["login"];
|
const username = authtoken["login"];
|
||||||
|
const repo = authtoken["repo"];
|
||||||
|
const api = new Forgejo("http://localhost:3000", "owner_user");
|
||||||
|
api.setTokenAuth(token);
|
||||||
|
|
||||||
test("use authentication without setting it ", () => {
|
test("use authentication without setting it ", () => {
|
||||||
const api = new Forgejo("http://localhost:3000", "owner_user");
|
const api = new Forgejo("http://localhost:3000", "owner_user");
|
||||||
|
@ -15,9 +18,50 @@ test("use authentication without setting it ", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test("verify /user API ", async () => {
|
test("verify /user API ", async () => {
|
||||||
const api = new Forgejo("http://localhost:3000", "owner_user");
|
|
||||||
api.setTokenAuth(token);
|
|
||||||
let user = await api.getUser();
|
let user = await api.getUser();
|
||||||
console.log(user);
|
|
||||||
expect(user["login"]).toBe(username);
|
expect(user["login"]).toBe(username);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("notifications API ", async () => {
|
||||||
|
let notifications = await api.getNotifications();
|
||||||
|
expect(notifications.length).toBe(5);
|
||||||
|
expect(await api.getNumUnreadNotifications()).toBe(5);
|
||||||
|
|
||||||
|
let notification = await api.getNotificationThread(notifications[0].id);
|
||||||
|
expect(notification).toEqual(notifications[0]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("issue API ", async () => {
|
||||||
|
let notifications = await api.getNotifications();
|
||||||
|
let issue = await api.getIssue(username, repo, 1);
|
||||||
|
expect(notifications[0].subject.type).toEqual("Issue");
|
||||||
|
expect(issue.title).toEqual(notifications[0].subject.title);
|
||||||
|
expect(issue.lazy_comments_data).toBeUndefined();
|
||||||
|
expect(issue.created_at instanceof Date).toBe(true);
|
||||||
|
expect(issue.updated_at instanceof Date).toBe(true);
|
||||||
|
if (issue.closed_at) {
|
||||||
|
// TODO: add issue closing functionality in integration/forgejo.py and verify this
|
||||||
|
expect(issue.closed_at instanceof Date).toBe(true);
|
||||||
|
}
|
||||||
|
// expect(typeof(issue.created_at)).toBe('Date');
|
||||||
|
});
|
||||||
|
|
||||||
|
test("comments API ", async () => {
|
||||||
|
let notifications = await api.getNotifications();
|
||||||
|
let issue = await api.getIssue(username, repo, 1);
|
||||||
|
issue = await api.getCommentsForIssue(issue);
|
||||||
|
expect(issue.lazy_comments_data.length).toBe(2);
|
||||||
|
|
||||||
|
issue.lazy_comments_data?.forEach((comment) => {
|
||||||
|
expect(comment.created_at instanceof Date).toBe(true);
|
||||||
|
expect(comment.updated_at instanceof Date).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("mentions in issue", async () => {
|
||||||
|
expect(await api.findMentionsInIssue(username, repo, 1)).toBe(true);
|
||||||
|
expect(await api.findMentionsInIssue(username, repo, 2)).toBe(true);
|
||||||
|
expect(await api.findMentionsInIssue(username, repo, 3)).toBe(true);
|
||||||
|
expect(await api.findMentionsInIssue(username, repo, 4)).toBe(true);
|
||||||
|
expect(await api.findMentionsInIssue(username, repo, 5)).toBe(false);
|
||||||
|
});
|
||||||
|
|
116
src/api.ts
116
src/api.ts
|
@ -3,6 +3,10 @@
|
||||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
|
||||||
import Auth from "./auth";
|
import Auth from "./auth";
|
||||||
|
import User from "./spec/user";
|
||||||
|
import Notification from "./spec/notification";
|
||||||
|
import Issue from "./spec/issue";
|
||||||
|
import Comment from "./spec/comments";
|
||||||
|
|
||||||
class Forgejo {
|
class Forgejo {
|
||||||
url: URL;
|
url: URL;
|
||||||
|
@ -16,7 +20,6 @@ class Forgejo {
|
||||||
*/
|
*/
|
||||||
constructor(url: string, username: string) {
|
constructor(url: string, username: string) {
|
||||||
this.url = new URL(url);
|
this.url = new URL(url);
|
||||||
console.log(this.url.toString());
|
|
||||||
this.username = username;
|
this.username = username;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,69 +46,85 @@ class Forgejo {
|
||||||
/**
|
/**
|
||||||
* Get logged in user
|
* Get logged in user
|
||||||
*/
|
*/
|
||||||
async getUser() {
|
async getUser(): Promise<User> {
|
||||||
this.url.pathname = "/api/v1/user";
|
this.url.pathname = "/api/v1/user";
|
||||||
console.log(this.url.toString());
|
|
||||||
let res = await fetch(this.url, {
|
let res = await fetch(this.url, {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
credentials: "include",
|
credentials: "include",
|
||||||
headers: this.getTokenAuthHeader(),
|
headers: this.getTokenAuthHeader(),
|
||||||
});
|
});
|
||||||
console.log(`got res: ${res}`);
|
|
||||||
return await res.json();
|
return await res.json();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all notifications
|
* Get all notifications
|
||||||
*/
|
*/
|
||||||
async getNotifications() {
|
async getNotifications(): Promise<Array<Notification>> {
|
||||||
this.url.pathname = "/api/v1/notifications";
|
this.url.pathname = "/api/v1/notifications";
|
||||||
let res = await fetch(this.url);
|
let res = await fetch(this.url, {
|
||||||
|
method: "GET",
|
||||||
|
credentials: "include",
|
||||||
|
headers: this.getTokenAuthHeader(),
|
||||||
|
});
|
||||||
|
|
||||||
return await res.json();
|
return await res.json();
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Get number of unread notifications
|
* Get number of unread notifications
|
||||||
*/
|
*/
|
||||||
async getNumUnreadNotifications() {
|
async getNumUnreadNotifications(): Promise<number> {
|
||||||
this.url.pathname = "/api/v1/notifications/new";
|
this.url.pathname = "/api/v1/notifications/new";
|
||||||
let res = await fetch(this.url);
|
let res = await fetch(this.url, {
|
||||||
return await res.json()["new"];
|
method: "GET",
|
||||||
|
credentials: "include",
|
||||||
|
headers: this.getTokenAuthHeader(),
|
||||||
|
});
|
||||||
|
|
||||||
|
let data = await res.json();
|
||||||
|
return data["new"];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get Notification Thread
|
* Get Notification Thread
|
||||||
* @param {number} id - The ID of a notification thread
|
* @param {number} id - The ID of a notification thread
|
||||||
*/
|
*/
|
||||||
async getNotificationThread(id: number) {
|
async getNotificationThread(id: number): Promise<Notification> {
|
||||||
this.url.pathname = `/api/v1/notifications/threads/${id}`;
|
this.url.pathname = `/api/v1/notifications/threads/${id}`;
|
||||||
let res = await fetch(this.url);
|
let res = await fetch(this.url, {
|
||||||
|
method: "GET",
|
||||||
|
credentials: "include",
|
||||||
|
headers: this.getTokenAuthHeader(),
|
||||||
|
});
|
||||||
return await res.json();
|
return await res.json();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the time at which the issue was last read
|
* Get the time at which the issue was last read
|
||||||
*/
|
*/
|
||||||
lastReadTime(issue: number): number {
|
lastReadTime(issue: Issue): Date {
|
||||||
return 10120123; // TODO: return last read UNIX epoch time from storage. If unread, return 0
|
return new Date("01/01/01"); // TODO: return last read time from storage. If unread, return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if logged in user is mentioned in the issue
|
* Check if logged in user is mentioned in the issue
|
||||||
*/
|
*/
|
||||||
async findMentionsInIssue(owner: string, repo: string, id: number) {
|
async findMentionsInIssue(owner: string, repo: string, id: number) {
|
||||||
let issue = this.getIssue(owner, repo, id);
|
let issue = await this.getIssue(owner, repo, id);
|
||||||
|
issue = await this.getCommentsForIssue(issue);
|
||||||
let unreadTime = this.lastReadTime(issue);
|
let unreadTime = this.lastReadTime(issue);
|
||||||
|
|
||||||
const mentionUtil = (str: string): boolean => str.includes(this.username);
|
const mentionUtil = (str: string): boolean => {
|
||||||
|
return str.includes(this.username);
|
||||||
|
};
|
||||||
|
|
||||||
const items = [];
|
const items = [];
|
||||||
|
|
||||||
if (issue.created > unreadTime) {
|
if (new Date(issue.created_at) > unreadTime) {
|
||||||
items.push(issue.title);
|
items.push(issue.title);
|
||||||
items.push(issue.body);
|
items.push(issue.body);
|
||||||
}
|
}
|
||||||
|
|
||||||
issue.commentsData.forEach((comment) => {
|
issue.lazy_comments_data.forEach((comment) => {
|
||||||
if (comment.created_at > unreadTime) {
|
if (comment.created_at > unreadTime) {
|
||||||
items.push(comment.body);
|
items.push(comment.body);
|
||||||
return;
|
return;
|
||||||
|
@ -118,12 +137,14 @@ class Forgejo {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let mention = false;
|
||||||
items.forEach((item) => {
|
items.forEach((item) => {
|
||||||
if (mentionUtil(item)) {
|
if (mentionUtil(item)) {
|
||||||
return true;
|
mention = true;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return false;
|
return mention;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -151,7 +172,62 @@ class Forgejo {
|
||||||
* @param {str} repo - The name of the repository
|
* @param {str} repo - The name of the repository
|
||||||
* @param {number} id - The ID of an issue
|
* @param {number} id - The ID of an issue
|
||||||
*/
|
*/
|
||||||
async getIssue(owner: string, repo: string, id: number) {}
|
async getIssue(owner: string, repo: string, id: number): Promise<Issue> {
|
||||||
|
this.url.pathname = `/api/v1/repos/${owner}/${repo}/issues/${id}`;
|
||||||
|
let res = await fetch(this.url, {
|
||||||
|
method: "GET",
|
||||||
|
credentials: "include",
|
||||||
|
headers: this.getTokenAuthHeader(),
|
||||||
|
});
|
||||||
|
let issue = await res.json();
|
||||||
|
|
||||||
|
if (typeof issue.created_at === "string") {
|
||||||
|
issue.created_at = new Date(issue.created_at);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (issue.updated_at) {
|
||||||
|
if (typeof issue.updated_at === "string") {
|
||||||
|
issue.updated_at = new Date(issue.updated_at);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (issue.closed_at) {
|
||||||
|
if (typeof issue.closed_at === "string") {
|
||||||
|
issue.closed_at = new Date(issue.closed_at);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return issue;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getCommentsForIssue(issue: Issue): Promise<Issue> {
|
||||||
|
// TODO: check if issue.number != issue.id causes problems. I'm assuming
|
||||||
|
// Issue.number is the local repository issue ID and issue.id is DB ID
|
||||||
|
this.url.pathname = `/api/v1/repos/${issue.repository.owner}/${issue.repository.name}/issues/${issue.number}/comments`;
|
||||||
|
let res = await fetch(this.url, {
|
||||||
|
method: "GET",
|
||||||
|
credentials: "include",
|
||||||
|
headers: this.getTokenAuthHeader(),
|
||||||
|
});
|
||||||
|
let c: Array<Comment> = await res.json();
|
||||||
|
|
||||||
|
c = c.map((comment) => {
|
||||||
|
if (typeof comment.created_at === "string") {
|
||||||
|
comment.created_at = new Date(comment.created_at);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (comment.updated_at) {
|
||||||
|
if (typeof comment.updated_at === "string") {
|
||||||
|
comment.updated_at = new Date(comment.updated_at);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return comment;
|
||||||
|
});
|
||||||
|
|
||||||
|
issue.lazy_comments_data = c;
|
||||||
|
|
||||||
|
return issue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Forgejo;
|
export default Forgejo;
|
||||||
|
|
Loading…
Reference in a new issue