+17
app/icon.svg
+17
app/icon.svg
···
1
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
2
+
<style>
3
+
path {
4
+
fill: hsl(var(--primary)); /* Default to primary theme color */
5
+
}
6
+
@media (prefers-color-scheme: dark) {
7
+
path {
8
+
fill: #FFFFFF; /* White for dark mode */
9
+
}
10
+
}
11
+
</style>
12
+
<path
13
+
fillRule="evenodd"
14
+
d="M1.5 9c0 0.69781 0.10996 1.3699 0.3135 2H0v1.5h2.52182c0.11848 0.1851 0.24608 0.3637 0.38217 0.5353L1 14.9393 2.06066 16l1.90399 -1.904C5.07323 14.975 6.47531 15.5 8 15.5s2.9268 -0.525 4.0353 -1.404L13.9393 16 15 14.9393l-1.904 -1.904c0.1361 -0.1716 0.2637 -0.3502 0.3822 -0.5353H16V11h-1.8135c0.2035 -0.6301 0.3135 -1.30219 0.3135 -2V0.5C12.2612 0.5 10.366 1.97145 9.7289 4H6.2711C5.63397 1.97145 3.73882 0.5 1.5 0.5V9ZM8 13l-2 -2h4l-2 2Z"
15
+
clipRule="evenodd"
16
+
/>
17
+
</svg>
+59
-5
lib/repositories/index.ts
+59
-5
lib/repositories/index.ts
···
1
1
// Import and re-export all repositories for easier imports
2
2
3
-
export * from './user-repository';
4
-
export * from './organization-repository';
5
-
export * from './repository-repository';
6
-
export * from './category-repository';
7
-
export * from './pr-repository';
3
+
export {
4
+
findUserById,
5
+
findUserByEmail,
6
+
createUser,
7
+
updateUser,
8
+
updateOrganizationRole,
9
+
getUserOrganizations,
10
+
addUserToOrganization,
11
+
removeUserFromOrganization,
12
+
getOrganizationRole,
13
+
findOrCreateUserByGitHubId,
14
+
} from './user-repository';
15
+
export {
16
+
findOrCreateOrganization,
17
+
findOrganizationById,
18
+
updateOrganization,
19
+
} from './organization-repository';
20
+
export {
21
+
findRepositoryById,
22
+
findRepositoryByGitHubId,
23
+
findOrCreateRepository,
24
+
updateRepository,
25
+
getOrganizationRepositories,
26
+
setRepositoryTracking,
27
+
getTrackedRepositories,
28
+
findRepositoryByFullName,
29
+
} from './repository-repository';
30
+
export {
31
+
createPullRequest,
32
+
findPullRequestById,
33
+
findPullRequestByNumber,
34
+
updatePullRequest,
35
+
getRepositoryPullRequests,
36
+
createPullRequestReview,
37
+
findReviewByGitHubId,
38
+
updatePullRequestReview,
39
+
} from './pr-repository';
40
+
export {
41
+
getDefaultCategories,
42
+
getOrganizationCategories,
43
+
createCategory,
44
+
updateCategory,
45
+
deleteCategory,
46
+
findCategoryById
47
+
} from './category-repository';
48
+
// Commented out sections for missing files remain for user to address
49
+
// export {
50
+
// getSettings,
51
+
// updateSetting,
52
+
// getOrganizationSettings,
53
+
// updateOrganizationSetting
54
+
// } from './settings-repository';
55
+
// export {
56
+
// createRecommendation,
57
+
// getRecommendationsByOrganizationId,
58
+
// updateRecommendationStatus
59
+
// } from './recommendation-repository';
60
+
61
+
// export * from './schema-version-repository';
+26
lib/repositories/user-repository.ts
+26
lib/repositories/user-repository.ts
···
127
127
'UPDATE user_organizations SET role = ? WHERE user_id = ? AND organization_id = ?',
128
128
[role, userId, organizationId]
129
129
);
130
+
}
131
+
132
+
export async function findOrCreateUserByGitHubId(userData: {
133
+
id: string; // GitHub user ID
134
+
login: string; // GitHub login/username
135
+
email?: string | null;
136
+
avatar_url?: string | null;
137
+
name?: string | null; // GitHub display name
138
+
}): Promise<User> {
139
+
const existingUser = await findUserById(userData.id);
140
+
if (existingUser) {
141
+
// Optionally update user details if they've changed
142
+
// For now, just return the existing user
143
+
return existingUser;
144
+
}
145
+
146
+
// User not found, create a new one
147
+
// The users table expects 'name', 'email', 'image'
148
+
// We'll use github login for name if display name is not available
149
+
// and github avatar_url for image
150
+
return createUser({
151
+
id: userData.id,
152
+
name: userData.name || userData.login,
153
+
email: userData.email || null,
154
+
image: userData.avatar_url || null,
155
+
});
130
156
}
+30
-3
lib/services/github-service.ts
+30
-3
lib/services/github-service.ts
···
11
11
setRepositoryTracking,
12
12
findRepositoryById,
13
13
findRepositoryByGitHubId,
14
-
addUserToOrganization
14
+
addUserToOrganization,
15
+
findOrCreateUserByGitHubId
15
16
} from '@/lib/repositories';
16
17
import { GitHubRepository, GitHubPullRequest, GitHubOrganization, GitHubUser, PRReview } from '@/lib/types';
17
18
···
101
102
? 'merged'
102
103
: pr.state === 'closed' ? 'closed' : 'open';
103
104
105
+
// Ensure author exists in our database
106
+
const prAuthor = pr.user ? await findOrCreateUserByGitHubId({
107
+
id: pr.user.id.toString(),
108
+
login: pr.user.login,
109
+
avatar_url: pr.user.avatar_url,
110
+
name: pr.user.name // pr.user might not have 'name', adjust if necessary based on GitHub API response
111
+
}) : null;
112
+
104
113
if (existingPR) {
105
114
// Update existing PR
106
115
await updatePullRequest(existingPR.id, {
···
111
120
closed_at: pr.closed_at,
112
121
merged_at: pr.merged_at,
113
122
draft: pr.draft,
123
+
// author_id is not typically updated, but if it could change or be initially null, handle here
114
124
});
115
125
} else {
116
126
// Create new PR
127
+
if (!prAuthor) {
128
+
console.warn(`Skipping PR #${pr.number} for repo ${owner}/${repo} due to missing author information from GitHub.`);
129
+
return; // Skip this PR if author couldn't be processed
130
+
}
117
131
const newPR = await createPullRequest({
118
132
github_id: pr.id,
119
133
repository_id: repositoryId,
120
134
number: pr.number,
121
135
title: pr.title,
122
136
description: pr.body || null,
123
-
author_id: pr.user.id.toString(), // This might require creating user records
137
+
author_id: prAuthor.id, // Use the ID from our users table
124
138
state,
125
139
created_at: pr.created_at,
126
140
updated_at: pr.updated_at,
···
154
168
const existingReview = await findReviewByGitHubId(review.id);
155
169
156
170
if (!existingReview) {
171
+
// Ensure reviewer exists in our database
172
+
const reviewAuthor = await findOrCreateUserByGitHubId({
173
+
id: review.user.id.toString(),
174
+
login: review.user.login,
175
+
avatar_url: review.user.avatar_url,
176
+
name: review.user.name // review.user might not have 'name', adjust if necessary
177
+
});
178
+
179
+
if (!reviewAuthor) {
180
+
console.warn(`Skipping review for PR #${prNumber} in ${owner}/${repo} by ${review.user.login} due to missing author information.`);
181
+
return; // Skip this review if author couldn't be processed
182
+
}
183
+
157
184
// Map GitHub review state to our enum
158
185
const reviewState = this.mapReviewState(review.state);
159
186
160
187
await createPullRequestReview({
161
188
github_id: review.id,
162
189
pull_request_id: pullRequestId,
163
-
reviewer_id: review.user.id.toString(), // This might require creating user records
190
+
reviewer_id: reviewAuthor.id, // Use the ID from our users table
164
191
state: reviewState,
165
192
submitted_at: review.submitted_at
166
193
});