diff --git a/api/tangled/actorprofile.go b/api/tangled/actorprofile.go --- a/api/tangled/actorprofile.go +++ b/api/tangled/actorprofile.go @@ -28,4 +28,5 @@ Location *string `json:"location,omitempty" cborgen:"location,omitempty"` // pinnedRepositories: Any ATURI, it is up to appviews to validate these fields. PinnedRepositories []string `json:"pinnedRepositories,omitempty" cborgen:"pinnedRepositories,omitempty"` Stats []string `json:"stats,omitempty" cborgen:"stats,omitempty"` + Pronouns *string `json:"pronouns,omitempty" cborgen:"pronouns,omitempty"` } diff --git a/appview/db/db.go b/appview/db/db.go --- a/appview/db/db.go +++ b/appview/db/db.go @@ -1106,6 +1106,13 @@ `) return err }) + runMigration(conn, logger, "add-pronouns-profile", func(tx *sql.Tx) error { + _, err := tx.Exec(` + alter table profile add column pronouns text; + `) + return err + }) + return &DB{ db, logger, diff --git a/appview/db/profile.go b/appview/db/profile.go --- a/appview/db/profile.go +++ b/appview/db/profile.go @@ -129,13 +129,15 @@ `insert or replace into profile ( did, description, include_bluesky, - location + location, + pronouns ) - values (?, ?, ?, ?)`, + values (?, ?, ?, ?, ?)`, profile.Did, profile.Description, includeBskyValue, profile.Location, + profile.Pronouns, ) if err != nil { @@ -216,7 +218,8 @@ id, did, description, include_bluesky, - location + location, + pronouns from profile %s`, @@ -231,14 +234,19 @@ profileMap := make(map[string]*models.Profile) for rows.Next() { var profile models.Profile var includeBluesky int + var pronouns sql.Null[string] - err = rows.Scan(&profile.ID, &profile.Did, &profile.Description, &includeBluesky, &profile.Location) + err = rows.Scan(&profile.ID, &profile.Did, &profile.Description, &includeBluesky, &profile.Location, &pronouns) if err != nil { return nil, err } if includeBluesky != 0 { profile.IncludeBluesky = true + } + + if pronouns.Valid { + profile.Pronouns = pronouns.V } profileMap[profile.Did] = &profile @@ -302,13 +310,16 @@ } func GetProfile(e Execer, did string) (*models.Profile, error) { var profile models.Profile + var pronouns sql.Null[string] + profile.Did = did includeBluesky := 0 + err := e.QueryRow( - `select description, include_bluesky, location from profile where did = ?`, + `select description, include_bluesky, location, pronouns from profile where did = ?`, did, - ).Scan(&profile.Description, &includeBluesky, &profile.Location) + ).Scan(&profile.Description, &includeBluesky, &profile.Location, &pronouns) if err == sql.ErrNoRows { profile := models.Profile{} profile.Did = did @@ -321,6 +332,10 @@ } if includeBluesky != 0 { profile.IncludeBluesky = true + } + + if pronouns.Valid { + profile.Pronouns = pronouns.V } rows, err := e.Query(`select link from profile_links where did = ?`, did) @@ -412,6 +427,11 @@ // ensure description is not too long if len(profile.Location) > 40 { return fmt.Errorf("Entered location is too long.") + } + + // ensure pronouns are not too long + if len(profile.Pronouns) > 40 { + return fmt.Errorf("Entered pronouns are too long.") } // ensure links are in order diff --git a/appview/ingester.go b/appview/ingester.go --- a/appview/ingester.go +++ b/appview/ingester.go @@ -291,6 +291,11 @@ } includeBluesky := record.Bluesky + pronouns := "" + if record.Pronouns != nil { + pronouns = *record.Pronouns + } + location := "" if record.Location != nil { location = *record.Location @@ -325,6 +330,7 @@ Location: location, Links: links, Stats: stats, PinnedRepos: pinned, + Pronouns: pronouns, } ddb, ok := i.Db.Execer.(*db.DB) diff --git a/appview/models/profile.go b/appview/models/profile.go --- a/appview/models/profile.go +++ b/appview/models/profile.go @@ -19,6 +19,7 @@ Location string Links [5]string Stats [2]VanityStat PinnedRepos [6]syntax.ATURI + Pronouns string } func (p Profile) IsLinksEmpty() bool { diff --git a/appview/pages/templates/user/fragments/editBio.html b/appview/pages/templates/user/fragments/editBio.html --- a/appview/pages/templates/user/fragments/editBio.html +++ b/appview/pages/templates/user/fragments/editBio.html @@ -20,6 +20,17 @@ placeholder="write a bio">{{ $description }}
+ +
+ {{ $pronouns := "" }} + {{ if and .Profile .Profile.Pronouns }} + {{ $pronouns = .Profile.Pronouns }} + {{ end }} + +
+
+ +
{{ $location := "" }} diff --git a/appview/pages/templates/user/fragments/profileCard.html b/appview/pages/templates/user/fragments/profileCard.html --- a/appview/pages/templates/user/fragments/profileCard.html +++ b/appview/pages/templates/user/fragments/profileCard.html @@ -12,6 +12,11 @@

{{ $userIdent }}

+ {{ with .Profile }} + {{ if .Pronouns }} +

{{ .Pronouns }}

+ {{ end }} + {{ end }} {{ i "rss" "size-4" }}
diff --git a/appview/state/profile.go b/appview/state/profile.go --- a/appview/state/profile.go +++ b/appview/state/profile.go @@ -538,6 +538,7 @@ profile.Description = r.FormValue("description") profile.IncludeBluesky = r.FormValue("includeBluesky") == "on" profile.Location = r.FormValue("location") + profile.Pronouns = r.FormValue("pronouns") var links [5]string for i := range 5 { @@ -652,6 +653,7 @@ Links: profile.Links[:], Location: &profile.Location, PinnedRepositories: pinnedRepoStrings, Stats: vanityStats[:], + Pronouns: &profile.Pronouns, }}, SwapRecord: cid, }) diff --git a/lexicons/actor/profile.json b/lexicons/actor/profile.json --- a/lexicons/actor/profile.json +++ b/lexicons/actor/profile.json @@ -64,6 +64,11 @@ "items": { "type": "string", "format": "at-uri" } + }, + "pronouns": { + "type": "string", + "description": "Preferred gender pronouns.", + "maxLength": 40 } } }