From 123eb78b54abe987ff4d81631f8651f543978f65 Mon Sep 17 00:00:00 2001 From: logikonline Date: Sun, 15 Mar 2026 22:19:20 -0400 Subject: [PATCH] feat(repo): add owner display name field for repositories Add OwnerDisplayName field to Repository model to allow custom display name for repository owner (e.g., "John Smith" instead of username). Used in license generation, social cards, and other public-facing contexts. Includes migration v368 to add column, UI in repository settings, and updates to license creation and social card rendering to use display name when available. --- models/migrations/migrations.go | 1 + models/migrations/v1_26/v368.go | 16 ++++++++++++++++ models/repo/repo.go | 1 + options/locale/custom_keys.json | 3 +++ options/locale/locale_en-US.json | 4 ++++ routers/web/org/setting_license.go | 6 +++++- routers/web/repo/setting/license.go | 6 +++++- routers/web/repo/setting/setting.go | 1 + routers/web/repo/socialcard.go | 7 ++++++- services/forms/repo_form.go | 1 + templates/repo/settings/license.tmpl | 1 + templates/repo/settings/options.tmpl | 5 +++++ 12 files changed, 49 insertions(+), 3 deletions(-) create mode 100644 models/migrations/v1_26/v368.go diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index f04960baac..b1f0ceb97d 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -442,6 +442,7 @@ func prepareMigrationTasks() []*migration { newMigration(365, "Add public_app_integration to repository", v1_26.AddPublicAppIntegrationToRepository), newMigration(366, "Add page experiment tables for A/B testing", v1_26.AddPageExperimentTables), newMigration(367, "Add pages translation table for multi-language support", v1_26.AddPagesTranslationTable), + newMigration(368, "Add owner_display_name to repository", v1_26.AddOwnerDisplayNameToRepository), } return preparedMigrations } diff --git a/models/migrations/v1_26/v368.go b/models/migrations/v1_26/v368.go new file mode 100644 index 0000000000..ffaaad52bc --- /dev/null +++ b/models/migrations/v1_26/v368.go @@ -0,0 +1,16 @@ +// Copyright 2026 MarketAlly. All rights reserved. +// SPDX-License-Identifier: MIT + +package v1_26 + +import ( + "xorm.io/xorm" +) + +func AddOwnerDisplayNameToRepository(x *xorm.Engine) error { + type Repository struct { + OwnerDisplayName string `xorm:"VARCHAR(255)"` + } + + return x.Sync(new(Repository)) +} diff --git a/models/repo/repo.go b/models/repo/repo.go index 45d0f51e00..f5fc7f1585 100644 --- a/models/repo/repo.go +++ b/models/repo/repo.go @@ -161,6 +161,7 @@ type Repository struct { Description string `xorm:"TEXT"` DisplayTitle string `xorm:"VARCHAR(255)"` GroupHeader string `xorm:"VARCHAR(255)"` + OwnerDisplayName string `xorm:"VARCHAR(255)"` LicenseType string `xorm:"VARCHAR(50)"` Website string `xorm:"VARCHAR(2048)"` OriginalServiceType api.GitServiceType `xorm:"index"` diff --git a/options/locale/custom_keys.json b/options/locale/custom_keys.json index 1e4cd668e2..0cc508a0e2 100644 --- a/options/locale/custom_keys.json +++ b/options/locale/custom_keys.json @@ -661,6 +661,9 @@ "repo.settings.display_title": "Display Title", "repo.settings.display_title_placeholder": "Optional display title for this repository", "repo.settings.display_title_help": "A custom title shown prominently on the repository page. Leave empty to use the repository name.", + "repo.settings.owner_display_name": "Owner Name", + "repo.settings.owner_display_name_placeholder": "e.g., John Smith, Acme Corp", + "repo.settings.owner_display_name_help": "A display name for the repository owner. Used in licenses, social cards, and other public-facing contexts instead of the username.", "repo.settings.license": "License", "repo.settings.license_type": "License Type", "repo.settings.license_none": "No license selected", diff --git a/options/locale/locale_en-US.json b/options/locale/locale_en-US.json index a217e52d85..351d302fe0 100644 --- a/options/locale/locale_en-US.json +++ b/options/locale/locale_en-US.json @@ -4286,6 +4286,9 @@ "repo.settings.group_header": "Group Header", "repo.settings.group_header_placeholder": "e.g., Core Services, Libraries, Tools", "repo.settings.group_header_help": "Optional header for grouping this repository on the organization page", + "repo.settings.owner_display_name": "Owner Name", + "repo.settings.owner_display_name_placeholder": "e.g., John Smith, Acme Corp", + "repo.settings.owner_display_name_help": "A display name for the repository owner. Used in licenses, social cards, and other public-facing contexts instead of the username.", "repo.settings.media_kit": "Media Kit", "repo.settings.media_kit.style": "Social Card Style", "repo.settings.media_kit.style_help": "Choose the visual style for your repository's share card image used in link previews.", @@ -4407,6 +4410,7 @@ "repo.settings.license_apply": "Apply", "repo.settings.license_overwrite_warning": "This will overwrite the existing %s file.", "repo.settings.license_create_confirm": "This will create a LICENSE.md file in the repository.", + "repo.settings.license_copyright_holder": "Copyright holder", "repo.settings.gallery": "Gallery", "repo.settings.gallery_help": "Upload images to showcase your project. Images are stored in the .gallery folder.", "repo.settings.gallery_upload": "Upload Images", diff --git a/routers/web/org/setting_license.go b/routers/web/org/setting_license.go index 6cf3fd8caf..321c846e23 100644 --- a/routers/web/org/setting_license.go +++ b/routers/web/org/setting_license.go @@ -159,8 +159,12 @@ func getOrCreateProfileRepo(ctx *context.Context, org *organization.Organization // createOrgLicenseFile creates a LICENSE.md file in the profile repo func createOrgLicenseFile(ctx *context.Context, repo *repo_model.Repository, licenseType string) error { // Get license content from templates + ownerName := repo.OwnerDisplayName + if ownerName == "" { + ownerName = repo.OwnerName + } licenseContent, err := repo_module.GetLicense(licenseType, &repo_module.LicenseValues{ - Owner: repo.OwnerName, + Owner: ownerName, Email: ctx.Doer.Email, Repo: repo.Name, Year: time.Now().Format("2006"), diff --git a/routers/web/repo/setting/license.go b/routers/web/repo/setting/license.go index 7f649f29ab..01fcbad55d 100644 --- a/routers/web/repo/setting/license.go +++ b/routers/web/repo/setting/license.go @@ -169,8 +169,12 @@ func LicenseCreate(ctx *context.Context) { func createLicenseFile(ctx *context.Context, repo *repo_model.Repository, licenseType string) error { // Get license content from templates + ownerName := repo.OwnerDisplayName + if ownerName == "" { + ownerName = repo.OwnerName + } licenseContent, err := repo_module.GetLicense(licenseType, &repo_module.LicenseValues{ - Owner: repo.OwnerName, + Owner: ownerName, Email: ctx.Doer.Email, Repo: repo.Name, Year: time.Now().Format("2006"), diff --git a/routers/web/repo/setting/setting.go b/routers/web/repo/setting/setting.go index 6c1c57693f..a620812e4f 100644 --- a/routers/web/repo/setting/setting.go +++ b/routers/web/repo/setting/setting.go @@ -206,6 +206,7 @@ func handleSettingsPostUpdate(ctx *context.Context) { repo.Description = form.Description repo.DisplayTitle = form.DisplayTitle repo.GroupHeader = form.GroupHeader + repo.OwnerDisplayName = form.OwnerDisplayName repo.Website = form.Website repo.IsTemplate = form.Template diff --git a/routers/web/repo/socialcard.go b/routers/web/repo/socialcard.go index 4b948a08ce..d471b22ad3 100644 --- a/routers/web/repo/socialcard.go +++ b/routers/web/repo/socialcard.go @@ -31,11 +31,16 @@ func SocialPreview(ctx *context.Context) { title = repo.Name } + repoFullName := repo.FullName() + if repo.OwnerDisplayName != "" { + repoFullName = repo.OwnerDisplayName + "/" + repo.Name + } + data := socialcard.CardData{ Title: title, Description: repo.Description, RepoAvatarURL: repo.AvatarLink(ctx), - RepoFullName: repo.FullName(), + RepoFullName: repoFullName, SolidColor: repo.SocialCardColor, UnsplashAuthor: repo.SocialCardUnsplashAuthor, } diff --git a/services/forms/repo_form.go b/services/forms/repo_form.go index 95f2cd68d9..4f903c4073 100644 --- a/services/forms/repo_form.go +++ b/services/forms/repo_form.go @@ -93,6 +93,7 @@ type RepoSettingForm struct { Description string `binding:"MaxSize(2048)"` DisplayTitle string `binding:"MaxSize(255)"` GroupHeader string `binding:"MaxSize(255)"` + OwnerDisplayName string `binding:"MaxSize(255)"` Website string `binding:"ValidUrl;MaxSize(1024)"` Interval string MirrorAddress string diff --git a/templates/repo/settings/license.tmpl b/templates/repo/settings/license.tmpl index 8f2242dd29..7b86541cd1 100644 --- a/templates/repo/settings/license.tmpl +++ b/templates/repo/settings/license.tmpl @@ -97,6 +97,7 @@ {{end}}

{{ctx.Locale.Tr "repo.settings.license_create_confirm"}}

+

{{ctx.Locale.Tr "repo.settings.license_copyright_holder"}}: {{if .Repository.OwnerDisplayName}}{{.Repository.OwnerDisplayName}}{{else}}{{.Repository.OwnerName}}{{end}}

diff --git a/templates/repo/settings/options.tmpl b/templates/repo/settings/options.tmpl index 40b53b4311..55da6d0bc2 100644 --- a/templates/repo/settings/options.tmpl +++ b/templates/repo/settings/options.tmpl @@ -36,6 +36,11 @@

{{ctx.Locale.Tr "repo.settings.group_header_help"}}

+
+ + +

{{ctx.Locale.Tr "repo.settings.owner_display_name_help"}}

+