Skip to content

Commit

Permalink
Merge pull request #20 from gentlementlegen/feat/save-permits-to-db
Browse files Browse the repository at this point in the history
feat: save permits to database
  • Loading branch information
gentlementlegen committed May 18, 2024
2 parents 142ad6d + 82a537e commit c1bc547
Show file tree
Hide file tree
Showing 10 changed files with 256 additions and 15 deletions.
5 changes: 3 additions & 2 deletions .github/workflows/jest-testing.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,11 @@ jobs:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
SUPABASE_URL: ${{ secrets.SUPABASE_URL }}
SUPABASE_KEY: ${{ secrets.SUPABASE_KEY }}
X25519_PRIVATE_KEY: ${{ secrets.X25519_PRIVATE_KEY }}
# Dummy values, not production ones!
X25519_PRIVATE_KEY: "wrQ9wTI1bwdAHbxk2dfsvoK1yRwDc0CEenmMXFvGYgY"
EVM_PRIVATE_ENCRYPTED: "kmpTKq5Wh9r9x5j3U9GqZr3NYnjK2g0HtbzeUBOuLC2y3x8ja_SKBNlB2AZ6LigXHP_HeMitftVUtzmoj8CFfVP9SqjWoL6IPku1hVTWkdTn97g1IxzmjydFxjdcf0wuDW1hvVtoq3Uw5yALABqxcQ"
NFT_MINTER_PRIVATE_KEY: ${{ secrets.NFT_MINTER_PRIVATE_KEY }}
NFT_CONTRACT_ADDRESS: ${{ secrets.NFT_CONTRACT_ADDRESS }}
EVM_PRIVATE_ENCRYPTED: ${{ secrets.EVM_PRIVATE_ENCRYPTED }}

steps:
- name: Checkout code
Expand Down
68 changes: 67 additions & 1 deletion src/parser/permit-generation-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
Database,
encodePermits,
generatePayoutPermit,
Permit,
SupportedEvents,
TokenType,
} from "@ubiquibot/permit-generation/core";
Expand All @@ -17,6 +18,7 @@ import {
} from "../configuration/permit-generation-configuration";
import { getOctokitInstance } from "../get-authentication-token";
import { IssueActivity } from "../issue-activity";
import { getRepo, parseGitHubUrl } from "../start";
import envConfigSchema, { EnvConfigType } from "../types/env-type";
import program from "./command-line";
import { Module, Result } from "./processor";
Expand All @@ -39,7 +41,7 @@ export class PermitGenerationModule implements Module {
evmPrivateEncrypted: configuration.evmPrivateEncrypted,
evmNetworkId: configuration.evmNetworkId,
};
const issueId = Number(payload.issueUrl.match(/[0-9]+$/)?.[1]);
const issueId = Number(payload.issueUrl.match(/[0-9]+$/)?.[0]);
payload.issue = {
id: issueId,
};
Expand Down Expand Up @@ -100,13 +102,77 @@ export class PermitGenerationModule implements Module {
config.permitRequests
);
result[key].permitUrl = `https://pay.ubq.fi?claim=${encodePermits(permits)}`;
await this._savePermitsToDatabase(result[key].userId, { issueUrl: payload.issueUrl, issueId }, permits);
} catch (e) {
console.error(e);
}
}
return result;
}

async _getOrCreateIssueLocation(issue: { issueId: number; issueUrl: string }) {
let locationId: number | null = null;

const { data: locationData } = await this._supabase
.from("locations")
.select("id")
.eq("issue_id", issue.issueId)
.eq("node_url", issue.issueUrl)
.single();

if (!locationData) {
const issueItem = await getRepo(parseGitHubUrl(issue.issueUrl));
const { data: newLocationData, error } = await this._supabase
.from("locations")
.insert({
node_url: issue.issueUrl,
issue_id: issue.issueId,
node_type: "Issue",
repository_id: issueItem.id,
})
.select("id")
.single();
if (!newLocationData || error) {
console.error("Failed to create a new location", error);
} else {
locationId = newLocationData.id;
}
} else {
locationId = locationData.id;
}
if (!locationId) {
throw new Error(`Failed to retrieve the related location from issue ${issue}`);
}
return locationId;
}

async _savePermitsToDatabase(userId: number, issue: { issueId: number; issueUrl: string }, permits: Permit[]) {
for (const permit of permits) {
try {
const { data: userData } = await this._supabase.from("users").select("id").eq("id", userId).single();
const locationId = await this._getOrCreateIssueLocation(issue);

if (userData) {
const { error } = await this._supabase.from("permits").insert({
amount: permit.amount.toString(),
nonce: permit.nonce,
deadline: permit.deadline,
signature: permit.signature,
beneficiary_id: userData.id,
location_id: locationId,
});
if (error) {
console.error("Failed to insert a new permit", error);
}
} else {
console.error(`Failed to save the permit: could not find user ${userId}`);
}
} catch (e) {
console.error("Failed to save permits to the database", e);
}
}
}

get enabled(): boolean {
if (!Value.Check(permitGenerationConfigurationType, this._configuration)) {
console.warn("Invalid configuration detected for PermitGenerationModule, disabling.");
Expand Down
6 changes: 6 additions & 0 deletions src/start.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
GitHubPullRequest,
GitHubPullRequestReviewComment,
GitHubPullRequestReviewState,
GitHubRepository,
GitHubTimelineEvent,
GitHubUser,
} from "./github-types";
Expand Down Expand Up @@ -57,6 +58,11 @@ import {
export type IssueParams = ReturnType<typeof parseGitHubUrl>;
export type PullParams = { owner: string; repo: string; pull_number: number };

export async function getRepo(params: IssueParams): Promise<GitHubRepository> {
const octokit = getOctokitInstance();
return (await octokit.repos.get(params)).data;
}

export async function getIssue(params: IssueParams): Promise<GitHubIssue> {
const octokit = getOctokitInstance();
return (await octokit.issues.get(params)).data;
Expand Down
9 changes: 9 additions & 0 deletions tests/__mocks__/db-seed.json
Original file line number Diff line number Diff line change
Expand Up @@ -119,5 +119,14 @@
"userId": 88761781,
"address": "0x4D0704f400D57Ba93eEa88765C3FcDBD826dCFc4"
}
],
"locations": [
{
"id": 1,
"issue_id": 22,
"node_url": "https://github.com/ubiquibot/comment-incentives/issues/22",
"node_type": "Issue",
"repository_id": 1
}
]
}
16 changes: 16 additions & 0 deletions tests/__mocks__/db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,20 @@ export const db = factory({
userId: Number,
address: String,
},
locations: {
id: primaryKey(Number),
issue_id: Number,
node_url: String,
node_type: String,
repository_id: Number,
},
permits: {
id: primaryKey(Number),
amount: String,
nonce: String,
deadline: String,
signature: String,
beneficiary_id: Number,
location_id: Number,
},
});
60 changes: 60 additions & 0 deletions tests/__mocks__/handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ export const handlers = [
http.get("https://api.github.com/repos/ubiquibot/comment-incentives/issues/22", () => {
return HttpResponse.json(issueGet);
}),
http.get("https://api.github.com/repos/ubiquibot/comment-incentives", () => {
return HttpResponse.json(issueGet);
}),
http.get("https://api.github.com/repos/ubiquibot/comment-incentives/issues/22/events", ({ params: { page } }) => {
return HttpResponse.json(!page ? issueEventsGet : issueEvents2Get);
}),
Expand Down Expand Up @@ -54,4 +57,61 @@ export const handlers = [
http.post("https://api.github.com/app/installations/48381972/access_tokens", () => {
return HttpResponse.json({});
}),
http.get("https://wfzpewmlyiozupulbuur.supabase.co/rest/v1/users", ({ request }) => {
const url = new URL(request.url);
const id = url.searchParams.get("id");
const userId = Number((id as string).match(/\d+/)?.[0]);
const user = db.users.findFirst({
where: {
id: {
equals: userId,
},
},
});
if (!user) {
return HttpResponse.json("User not found", { status: 404 });
}
return HttpResponse.json(user);
}),
http.get("https://wfzpewmlyiozupulbuur.supabase.co/rest/v1/locations", ({ request }) => {
const url = new URL(request.url);
const issue = url.searchParams.get("issue_id");
const node = url.searchParams.get("node_url");
if (!issue) {
return HttpResponse.json(db.locations.findMany({}));
}
const issueId = Number((issue as string).match(/\d+/)?.[0]);
const nodeUrl = (node as string).match(/https.+/)?.[0];
const location = db.locations.findFirst({
where: {
node_url: {
equals: nodeUrl,
},
issue_id: {
equals: issueId,
},
},
});
if (!location) {
return HttpResponse.json("Location not found", { status: 404 });
}
return HttpResponse.json(location);
}),
http.post("https://wfzpewmlyiozupulbuur.supabase.co/rest/v1/locations", async ({ request }) => {
const data = await request.json();
if (!data) {
return HttpResponse.error();
}
const createdLocation = db.locations.create(data as Record<string, string>);
return HttpResponse.json(createdLocation);
}),
http.post("https://wfzpewmlyiozupulbuur.supabase.co/rest/v1/permits", async ({ request }) => {
const data = (await request.json()) as Record<string, string | number>;
if (!data) {
return HttpResponse.error();
}
data.id = db.permits.count() + 1;
const createdPermit = db.permits.create(data);
return HttpResponse.json(createdPermit);
}),
];
Loading

1 comment on commit c1bc547

@github-actions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lines Statements Branches Functions
Coverage: 78%
78.02% (355/455) 65.86% (137/208) 81.05% (77/95)

JUnit

Tests Skipped Failures Errors Time
22 0 💤 0 ❌ 0 🔥 7.647s ⏱️
Coverage Report (78%)
File% Stmts% Branch% Funcs% LinesUncovered Line #s
All files78.0265.8681.0578.23 
src76.2378.5773.3378.35 
   get-authentication-token.ts100100100100 
   github-types.ts100100100100 
   index.ts41.665033.3341.6612–16, 22–26
   issue-activity.ts96.0781.811009646–47
   start.ts54.545057.146062–63, 100–118, 130
src/configuration83.335010082.6 
   comment-types.ts0000 
   config-reader.ts66.665010066.6612, 20–22
   constants.ts100100100100 
   content-evaluator-config.ts100100100100 
   data-purge-config.ts100100100100 
   formatting-evaluator-config.ts100100100100 
   github-comment-config.ts100100100100 
   incentives.ts100100100100 
   permit-generation-configuration.ts100100100100 
   user-extractor-config.ts100100100100 
src/data-collection83.3365.3810082.85 
   collect-linked-pulls.ts83.3365.3810082.8510, 19, 60–64
src/parser77.4364.1882.1477.14 
   content-evaluator-module.ts62.6845.4558.336023–24, 56–57, 75–112, 141–145
   data-purge-module.ts81.8190.910081.8115–16
   formatting-evaluator-module.ts92.56010092.374–75, 87
   github-comment-module.ts84.746510084.7439–50, 58–59, 68, 119
   permit-generation-module.ts6637.555.556650–51, 58–65, 107, 124–138, 144, 165–171, 178–179
   processor.ts91.6683.3310091.6634–35, 72
   user-extractor-module.ts7676.1983.337616–17, 34, 47, 49–50
src/types83.335010083.33 
   env-type.ts100100100100 
   payout.ts80501008018

Please sign in to comment.