Skip to content

Commit

Permalink
hicli: use user avatar as room avatar in DMs
Browse files Browse the repository at this point in the history
  • Loading branch information
tulir committed Oct 14, 2024
1 parent 68f1ff3 commit 89f78e9
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 21 deletions.
23 changes: 14 additions & 9 deletions hicli/database/room.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import (

const (
getRoomBaseQuery = `
SELECT room_id, creation_content, name, name_quality, avatar, topic, canonical_alias,
SELECT room_id, creation_content, name, name_quality, avatar, explicit_avatar, topic, canonical_alias,
lazy_load_summary, encryption_event, has_member_list,
preview_event_rowid, sorting_timestamp, prev_batch
FROM room
Expand All @@ -39,14 +39,15 @@ const (
name = COALESCE($3, room.name),
name_quality = CASE WHEN $3 IS NOT NULL THEN $4 ELSE room.name_quality END,
avatar = COALESCE($5, room.avatar),
topic = COALESCE($6, room.topic),
canonical_alias = COALESCE($7, room.canonical_alias),
lazy_load_summary = COALESCE($8, room.lazy_load_summary),
encryption_event = COALESCE($9, room.encryption_event),
has_member_list = room.has_member_list OR $10,
preview_event_rowid = COALESCE($11, room.preview_event_rowid),
sorting_timestamp = COALESCE($12, room.sorting_timestamp),
prev_batch = COALESCE($13, room.prev_batch)
explicit_avatar = CASE WHEN $5 IS NOT NULL THEN $6 ELSE room.explicit_avatar END,
topic = COALESCE($7, room.topic),
canonical_alias = COALESCE($8, room.canonical_alias),
lazy_load_summary = COALESCE($9, room.lazy_load_summary),
encryption_event = COALESCE($10, room.encryption_event),
has_member_list = room.has_member_list OR $11,
preview_event_rowid = COALESCE($12, room.preview_event_rowid),
sorting_timestamp = COALESCE($13, room.sorting_timestamp),
prev_batch = COALESCE($14, room.prev_batch)
WHERE room_id = $1
`
setRoomPrevBatchQuery = `
Expand Down Expand Up @@ -133,6 +134,7 @@ type Room struct {
Name *string `json:"name,omitempty"`
NameQuality NameQuality `json:"name_quality"`
Avatar *id.ContentURI `json:"avatar,omitempty"`
ExplicitAvatar bool `json:"explicit_avatar"`
Topic *string `json:"topic,omitempty"`
CanonicalAlias *id.RoomAlias `json:"canonical_alias,omitempty"`

Expand All @@ -155,6 +157,7 @@ func (r *Room) CheckChangesAndCopyInto(other *Room) (hasChanges bool) {
}
if r.Avatar != nil {
other.Avatar = r.Avatar
other.ExplicitAvatar = r.ExplicitAvatar
hasChanges = true
}
if r.Topic != nil {
Expand Down Expand Up @@ -201,6 +204,7 @@ func (r *Room) Scan(row dbutil.Scannable) (*Room, error) {
&r.Name,
&r.NameQuality,
&r.Avatar,
&r.ExplicitAvatar,
&r.Topic,
&r.CanonicalAlias,
dbutil.JSON{Data: &r.LazyLoadSummary},
Expand All @@ -226,6 +230,7 @@ func (r *Room) sqlVariables() []any {
r.Name,
r.NameQuality,
r.Avatar,
r.ExplicitAvatar,
r.Topic,
r.CanonicalAlias,
dbutil.JSONPtr(r.LazyLoadSummary),
Expand Down
3 changes: 2 additions & 1 deletion hicli/database/upgrades/00-latest-revision.sql
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
-- v0 -> v1: Latest revision
-- v0 -> v2 (compatible with v1+): Latest revision
CREATE TABLE account (
user_id TEXT NOT NULL PRIMARY KEY,
device_id TEXT NOT NULL,
Expand All @@ -15,6 +15,7 @@ CREATE TABLE room (
name TEXT,
name_quality INTEGER NOT NULL DEFAULT 0,
avatar TEXT,
explicit_avatar INTEGER NOT NULL DEFAULT 0,
topic TEXT,
canonical_alias TEXT,
lazy_load_summary TEXT,
Expand Down
2 changes: 2 additions & 0 deletions hicli/database/upgrades/02-explicit-avatar-flag.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- v2 (compatible with v1+): Add explicit avatar flag to rooms
ALTER TABLE room ADD COLUMN explicit_avatar INTEGER NOT NULL DEFAULT 0;
34 changes: 23 additions & 11 deletions hicli/sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -556,12 +556,15 @@ func (h *HiClient) processStateAndTimeline(ctx context.Context, room *database.R
}
// Calculate name from participants if participants changed and current name was generated from participants, or if the room name was unset
if (heroesChanged && updatedRoom.NameQuality <= database.NameQualityParticipants) || updatedRoom.NameQuality == database.NameQualityNil {
name, err := h.calculateRoomParticipantName(ctx, room.ID, summary)
name, dmAvatarURL, err := h.calculateRoomParticipantName(ctx, room.ID, summary)
if err != nil {
return fmt.Errorf("failed to calculate room name: %w", err)
}
updatedRoom.Name = &name
updatedRoom.NameQuality = database.NameQualityParticipants
if !dmAvatarURL.IsEmpty() && !room.ExplicitAvatar {
updatedRoom.Avatar = &dmAvatarURL
}
}
if timeline.PrevBatch != "" && (room.PrevBatch == "" || timeline.Limited) {
updatedRoom.PrevBatch = timeline.PrevBatch
Expand Down Expand Up @@ -595,14 +598,15 @@ func joinMemberNames(names []string, totalCount int) string {
}
}

func (h *HiClient) calculateRoomParticipantName(ctx context.Context, roomID id.RoomID, summary *mautrix.LazyLoadSummary) (string, error) {
func (h *HiClient) calculateRoomParticipantName(ctx context.Context, roomID id.RoomID, summary *mautrix.LazyLoadSummary) (string, id.ContentURI, error) {
var primaryAvatarURL id.ContentURI
if summary == nil || len(summary.Heroes) == 0 {
return "Empty room", nil
return "Empty room", primaryAvatarURL, nil
}
var functionalMembers []id.UserID
functionalMembersEvt, err := h.DB.CurrentState.Get(ctx, roomID, event.StateElementFunctionalMembers, "")
if err != nil {
return "", fmt.Errorf("failed to get %s event: %w", event.StateElementFunctionalMembers.Type, err)
return "", primaryAvatarURL, fmt.Errorf("failed to get %s event: %w", event.StateElementFunctionalMembers.Type, err)
} else if functionalMembersEvt != nil {
mautrixEvt := functionalMembersEvt.AsRawMautrix()
_ = mautrixEvt.Content.ParseRaw(mautrixEvt.Type)
Expand All @@ -627,28 +631,35 @@ func (h *HiClient) calculateRoomParticipantName(ctx context.Context, roomID id.R
}
heroEvt, err := h.DB.CurrentState.Get(ctx, roomID, event.StateMember, hero.String())
if err != nil {
return "", fmt.Errorf("failed to get %s's member event: %w", hero, err)
return "", primaryAvatarURL, fmt.Errorf("failed to get %s's member event: %w", hero, err)
} else if heroEvt == nil {
leftMembers = append(leftMembers, hero.String())
continue
}
results := gjson.GetManyBytes(heroEvt.Content, "membership", "displayname")
name := results[1].Str
membership := gjson.GetBytes(heroEvt.Content, "membership").Str
name := gjson.GetBytes(heroEvt.Content, "displayname").Str
if name == "" {
name = hero.String()
}
if results[0].Str == "join" || results[0].Str == "invite" {
avatarURL := gjson.GetBytes(heroEvt.Content, "avatar_url").Str
if avatarURL != "" {
primaryAvatarURL = id.ContentURIString(avatarURL).ParseOrIgnore()
}
if membership == "join" || membership == "invite" {
members = append(members, name)
} else {
leftMembers = append(leftMembers, name)
}
}
if len(members)+len(leftMembers) > 1 || !primaryAvatarURL.IsValid() {
primaryAvatarURL = id.ContentURI{}
}
if len(members) > 0 {
return joinMemberNames(members, memberCount), nil
return joinMemberNames(members, memberCount), primaryAvatarURL, nil
} else if len(leftMembers) > 0 {
return fmt.Sprintf("Empty room (was %s)", joinMemberNames(leftMembers, memberCount)), nil
return fmt.Sprintf("Empty room (was %s)", joinMemberNames(leftMembers, memberCount)), primaryAvatarURL, nil
} else {
return "Empty room", nil
return "Empty room", primaryAvatarURL, nil
}
}

Expand Down Expand Up @@ -721,6 +732,7 @@ func processImportantEvent(ctx context.Context, evt *event.Event, existingRoomDa
if ok {
url, _ := content.URL.Parse()
updatedRoom.Avatar = &url
updatedRoom.ExplicitAvatar = true
}
case event.StateTopic:
content, ok := evt.Content.Parsed.(*event.TopicEventContent)
Expand Down

0 comments on commit 89f78e9

Please sign in to comment.