@@ -82,8 +82,9 @@ type contributionDay struct { |
| 82 | 82 | } |
| 83 | 83 | |
| 84 | 84 | type profileContributionRepo struct { |
| 85 | | - Repo reposdb.Repo |
| 86 | | - OwnerSlug string |
| 85 | + Repo reposdb.Repo |
| 86 | + OwnerSlug string |
| 87 | + AllowIdentityFallback bool |
| 87 | 88 | } |
| 88 | 89 | |
| 89 | 90 | func (h *Handlers) visibleUserRepos(ctx context.Context, userID int64, viewer middleware.CurrentUser) []reposdb.Repo { |
@@ -236,7 +237,7 @@ func (h *Handlers) contributionCalendar(ctx context.Context, user usersdb.User, |
| 236 | 237 | continue |
| 237 | 238 | } |
| 238 | 239 | for _, commit := range commits { |
| 239 | | - if !commitMatchesProfileUser(commit, emails, user) { |
| 240 | + if !commitMatchesProfileUser(commit, emails, user, source.AllowIdentityFallback) { |
| 240 | 241 | continue |
| 241 | 242 | } |
| 242 | 243 | day := time.Date(commit.AuthorWhen.UTC().Year(), commit.AuthorWhen.UTC().Month(), commit.AuthorWhen.UTC().Day(), 0, 0, 0, 0, time.UTC) |
@@ -305,7 +306,7 @@ func (h *Handlers) profileContributionRepos(ctx context.Context, user usersdb.Us |
| 305 | 306 | queries := reposdb.New() |
| 306 | 307 | seen := map[int64]struct{}{} |
| 307 | 308 | out := make([]profileContributionRepo, 0, 64) |
| 308 | | - add := func(ownerSlug string, repo reposdb.Repo) { |
| 309 | + add := func(ownerSlug string, repo reposdb.Repo, allowIdentityFallback bool) { |
| 309 | 310 | if ownerSlug == "" { |
| 310 | 311 | return |
| 311 | 312 | } |
@@ -316,7 +317,11 @@ func (h *Handlers) profileContributionRepos(ctx context.Context, user usersdb.Us |
| 316 | 317 | return |
| 317 | 318 | } |
| 318 | 319 | seen[repo.ID] = struct{}{} |
| 319 | | - out = append(out, profileContributionRepo{Repo: repo, OwnerSlug: ownerSlug}) |
| 320 | + out = append(out, profileContributionRepo{ |
| 321 | + Repo: repo, |
| 322 | + OwnerSlug: ownerSlug, |
| 323 | + AllowIdentityFallback: allowIdentityFallback, |
| 324 | + }) |
| 320 | 325 | } |
| 321 | 326 | |
| 322 | 327 | userRepos, err := queries.ListReposForOwnerUser(ctx, h.d.Pool, pgtype.Int8{Int64: user.ID, Valid: true}) |
@@ -324,7 +329,7 @@ func (h *Handlers) profileContributionRepos(ctx context.Context, user usersdb.Us |
| 324 | 329 | h.d.Logger.WarnContext(ctx, "profile overview: contribution user repos", "user_id", user.ID, "error", err) |
| 325 | 330 | } else { |
| 326 | 331 | for _, repo := range userRepos { |
| 327 | | - add(user.Username, repo) |
| 332 | + add(user.Username, repo, true) |
| 328 | 333 | } |
| 329 | 334 | } |
| 330 | 335 | |
@@ -339,7 +344,7 @@ func (h *Handlers) profileContributionRepos(ctx context.Context, user usersdb.Us |
| 339 | 344 | continue |
| 340 | 345 | } |
| 341 | 346 | for _, repo := range orgRepos { |
| 342 | | - add(org.Slug, repo) |
| 347 | + add(org.Slug, repo, true) |
| 343 | 348 | } |
| 344 | 349 | } |
| 345 | 350 | } |
@@ -350,7 +355,7 @@ func (h *Handlers) profileContributionRepos(ctx context.Context, user usersdb.Us |
| 350 | 355 | return out |
| 351 | 356 | } |
| 352 | 357 | for _, row := range publicRepos { |
| 353 | | - add(row.OwnerSlug, row.Repo) |
| 358 | + add(row.OwnerSlug, row.Repo, false) |
| 354 | 359 | } |
| 355 | 360 | return out |
| 356 | 361 | } |
@@ -387,19 +392,33 @@ func contributionYears(username string, currentYear, selectedYear int) []contrib |
| 387 | 392 | return years |
| 388 | 393 | } |
| 389 | 394 | |
| 390 | | -func commitMatchesProfileUser(commit repogit.Commit, verifiedEmails map[string]struct{}, user usersdb.User) bool { |
| 395 | +func commitMatchesProfileUser(commit repogit.Commit, verifiedEmails map[string]struct{}, user usersdb.User, allowIdentityFallback bool) bool { |
| 391 | 396 | if len(verifiedEmails) > 0 { |
| 392 | | - _, ok := verifiedEmails[strings.ToLower(strings.TrimSpace(commit.AuthorEmail))] |
| 393 | | - return ok |
| 397 | + if _, ok := verifiedEmails[strings.ToLower(strings.TrimSpace(commit.AuthorEmail))]; ok { |
| 398 | + return true |
| 399 | + } |
| 394 | 400 | } |
| 395 | | - name := strings.ToLower(strings.TrimSpace(commit.AuthorName)) |
| 396 | | - if name == "" { |
| 401 | + if !allowIdentityFallback { |
| 397 | 402 | return false |
| 398 | 403 | } |
| 404 | + name := strings.ToLower(strings.TrimSpace(commit.AuthorName)) |
| 399 | 405 | if name == strings.ToLower(user.Username) { |
| 400 | 406 | return true |
| 401 | 407 | } |
| 402 | | - return user.DisplayName != "" && name == strings.ToLower(strings.TrimSpace(user.DisplayName)) |
| 408 | + if user.DisplayName != "" && name == strings.ToLower(strings.TrimSpace(user.DisplayName)) { |
| 409 | + return true |
| 410 | + } |
| 411 | + return commitEmailNamesProfileUser(commit.AuthorEmail, user.Username) |
| 412 | +} |
| 413 | + |
| 414 | +func commitEmailNamesProfileUser(email, username string) bool { |
| 415 | + email = strings.ToLower(strings.TrimSpace(email)) |
| 416 | + username = strings.ToLower(strings.TrimSpace(username)) |
| 417 | + if email == "" || username == "" { |
| 418 | + return false |
| 419 | + } |
| 420 | + return strings.HasSuffix(email, "+"+username+"@users.noreply.github.com") || |
| 421 | + email == username+"@users.noreply.github.com" |
| 403 | 422 | } |
| 404 | 423 | |
| 405 | 424 | func (h *Handlers) verifiedEmails(ctx context.Context, userID int64) map[string]struct{} { |