feat: add license headers with reuse
This commit is contained in:
parent
53a21b7c4a
commit
f380f2ef01
17 changed files with 59 additions and 241 deletions
|
@ -0,0 +1,3 @@
|
||||||
|
# SPDX-FileCopyrightText: 2023 Aravinth Manivannan <realaravinth@batsense.net>
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
@ -1,3 +1,7 @@
|
||||||
|
# SPDX-FileCopyrightText: 2023 Aravinth Manivannan <realaravinth@batsense.net>
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
from .cli import Cli
|
from .cli import Cli
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
|
# SPDX-FileCopyrightText: 2023 Aravinth Manivannan <realaravinth@batsense.net>
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
|
||||||
set -Exeuo pipefail
|
set -Exeuo pipefail
|
||||||
|
|
||||||
source integration/lib.sh
|
source integration/lib.sh
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
# SPDX-FileCopyrightText: 2023 Aravinth Manivannan <realaravinth@batsense.net>
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
from requests import Session
|
from requests import Session
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
; SPDX-FileCopyrightText: 2023 Aravinth Manivannan <realaravinth@batsense.net>
|
||||||
|
;
|
||||||
|
; SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
|
||||||
APP_NAME = Forgejo:+Beyond+Coding+We+Forge
|
APP_NAME = Forgejo:+Beyond+Coding+We+Forge
|
||||||
RUN_USER = git
|
RUN_USER = git
|
||||||
RUN_MODE = prod
|
RUN_MODE = prod
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
# SPDX-FileCopyrightText: 2023 Aravinth Manivannan <realaravinth@batsense.net>
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
|
||||||
from html.parser import HTMLParser
|
from html.parser import HTMLParser
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
# SPDX-FileCopyrightText: 2023 Aravinth Manivannan <realaravinth@batsense.net>
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import random
|
import random
|
||||||
import json
|
import json
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
# SPDX-FileCopyrightText: 2023 Aravinth Manivannan <realaravinth@batsense.net>
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
|
||||||
is_ci(){
|
is_ci(){
|
||||||
if [ -z ${CI+x} ];
|
if [ -z ${CI+x} ];
|
||||||
then
|
then
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
|
# SPDX-FileCopyrightText: 2023 Aravinth Manivannan <realaravinth@batsense.net>
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
|
||||||
set -Exeuo pipefail
|
set -Exeuo pipefail
|
||||||
|
|
||||||
source integration/lib.sh
|
source integration/lib.sh
|
||||||
|
|
233
src/api.ts
233
src/api.ts
|
@ -1,233 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: 2023 Aravinth Manivannan <realaravinth@batsense.net>
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
||||||
|
|
||||||
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 {
|
|
||||||
url: URL;
|
|
||||||
username: string;
|
|
||||||
token?: Auth;
|
|
||||||
/**
|
|
||||||
* Represents a Forgejo instance.
|
|
||||||
* @constructor
|
|
||||||
* @param {string} url - The URL of the Forgejo instance
|
|
||||||
* @param {string} username - username of the logged in user
|
|
||||||
*/
|
|
||||||
constructor(url: string, username: string) {
|
|
||||||
this.url = new URL(url);
|
|
||||||
this.username = username;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Authenticate with token
|
|
||||||
* @param {Auth} token - access token
|
|
||||||
*/
|
|
||||||
setTokenAuth(token: string) {
|
|
||||||
this.token = new Auth(token);
|
|
||||||
}
|
|
||||||
|
|
||||||
getTokenAuth(): Auth {
|
|
||||||
if (this.token) {
|
|
||||||
return this.token;
|
|
||||||
} else {
|
|
||||||
throw new Error("set authentication token before use");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getTokenAuthHeader() {
|
|
||||||
return { Authorization: `token ${this.getTokenAuth().getToken()}` };
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get logged in user
|
|
||||||
*/
|
|
||||||
async getUser(): Promise<User> {
|
|
||||||
this.url.pathname = "/api/v1/user";
|
|
||||||
let res = await fetch(this.url, {
|
|
||||||
method: "GET",
|
|
||||||
credentials: "include",
|
|
||||||
headers: this.getTokenAuthHeader(),
|
|
||||||
});
|
|
||||||
return await res.json();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get all notifications
|
|
||||||
*/
|
|
||||||
async getNotifications(): Promise<Array<Notification>> {
|
|
||||||
this.url.pathname = "/api/v1/notifications";
|
|
||||||
let res = await fetch(this.url, {
|
|
||||||
method: "GET",
|
|
||||||
credentials: "include",
|
|
||||||
headers: this.getTokenAuthHeader(),
|
|
||||||
});
|
|
||||||
|
|
||||||
return await res.json();
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Get number of unread notifications
|
|
||||||
*/
|
|
||||||
async getNumUnreadNotifications(): Promise<number> {
|
|
||||||
this.url.pathname = "/api/v1/notifications/new";
|
|
||||||
let res = await fetch(this.url, {
|
|
||||||
method: "GET",
|
|
||||||
credentials: "include",
|
|
||||||
headers: this.getTokenAuthHeader(),
|
|
||||||
});
|
|
||||||
|
|
||||||
let data = await res.json();
|
|
||||||
return data["new"];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get Notification Thread
|
|
||||||
* @param {number} id - The ID of a notification thread
|
|
||||||
*/
|
|
||||||
async getNotificationThread(id: number): Promise<Notification> {
|
|
||||||
this.url.pathname = `/api/v1/notifications/threads/${id}`;
|
|
||||||
let res = await fetch(this.url, {
|
|
||||||
method: "GET",
|
|
||||||
credentials: "include",
|
|
||||||
headers: this.getTokenAuthHeader(),
|
|
||||||
});
|
|
||||||
return await res.json();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the time at which the issue was last read
|
|
||||||
*/
|
|
||||||
lastReadTime(issue: Issue): Date {
|
|
||||||
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
|
|
||||||
*/
|
|
||||||
async findMentionsInIssue(owner: string, repo: string, id: number) {
|
|
||||||
let issue = await this.getIssue(owner, repo, id);
|
|
||||||
issue = await this.getCommentsForIssue(issue);
|
|
||||||
let unreadTime = this.lastReadTime(issue);
|
|
||||||
|
|
||||||
const mentionUtil = (str: string): boolean => {
|
|
||||||
return str.includes(this.username);
|
|
||||||
};
|
|
||||||
|
|
||||||
const items = [];
|
|
||||||
|
|
||||||
if (new Date(issue.created_at) > unreadTime) {
|
|
||||||
items.push(issue.title);
|
|
||||||
items.push(issue.body);
|
|
||||||
}
|
|
||||||
|
|
||||||
issue.lazy_comments_data.forEach((comment) => {
|
|
||||||
if (comment.created_at > unreadTime) {
|
|
||||||
items.push(comment.body);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (comment.updated_at) {
|
|
||||||
if (comment.updated_at > unreadTime) {
|
|
||||||
items.push(comment.body);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let mention = false;
|
|
||||||
items.forEach((item) => {
|
|
||||||
if (mentionUtil(item)) {
|
|
||||||
mention = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return mention;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Mark Notification Read
|
|
||||||
* @param {number} id - The ID of a notification thread
|
|
||||||
*/
|
|
||||||
async markNotificationRead(id: number) {
|
|
||||||
this.url.pathname = `/api/v1/notifications/threads/${id}`;
|
|
||||||
await fetch(this.url, { method: "PATCH" });
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Mark Notification Read for a specific repository
|
|
||||||
* @param {string} owner - Name of the owner of the repository
|
|
||||||
* @param {string} repo - Name of the repository
|
|
||||||
*/
|
|
||||||
async markNotificationReadForRepo(owner: string, repo: string) {
|
|
||||||
this.url.pathname = `/api/v1/repos/${owner}/${repo}/notifications`;
|
|
||||||
await fetch(this.url, { method: "PUT" });
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get Issue and its comments
|
|
||||||
* @param {str} owner - The owner of the repository
|
|
||||||
* @param {str} repo - The name of the repository
|
|
||||||
* @param {number} id - The ID of an issue
|
|
||||||
*/
|
|
||||||
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;
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
// SPDX-FileCopyrightText: 2023 Aravinth Manivannan <realaravinth@batsense.net>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
|
||||||
class Auth {
|
class Auth {
|
||||||
token: string;
|
token: string;
|
||||||
constructor(token: string) {
|
constructor(token: string) {
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
// SPDX-FileCopyrightText: 2023 Aravinth Manivannan <realaravinth@batsense.net>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
|
||||||
import User from "./user";
|
import User from "./user";
|
||||||
|
|
||||||
type Comment = {
|
type Comment = {
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
// SPDX-FileCopyrightText: 2023 Aravinth Manivannan <realaravinth@batsense.net>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
|
||||||
import User from "./user";
|
import User from "./user";
|
||||||
import Comment from "./comments";
|
import Comment from "./comments";
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
// SPDX-FileCopyrightText: 2023 Aravinth Manivannan <realaravinth@batsense.net>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
|
||||||
import Repository from "./repository";
|
import Repository from "./repository";
|
||||||
|
|
||||||
type Subject = {
|
type Subject = {
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
type Repository = {
|
|
||||||
id: number;
|
|
||||||
name: string;
|
|
||||||
full_name: string;
|
|
||||||
html_url: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Repository;
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
// SPDX-FileCopyrightText: 2023 Aravinth Manivannan <realaravinth@batsense.net>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
|
||||||
import User from "./user";
|
import User from "./user";
|
||||||
|
|
||||||
type Repository = {
|
type Repository = {
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
// SPDX-FileCopyrightText: 2023 Aravinth Manivannan <realaravinth@batsense.net>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
|
||||||
type User = {
|
type User = {
|
||||||
id: number;
|
id: number;
|
||||||
login: string;
|
login: string;
|
||||||
|
|
Loading…
Reference in a new issue