core: render web previews for channels (#7029)

* plan: web previews for channels

* types for recipient side to support channel web previews and domain names

* fix

* migrations

* update schema and api types

* update schema

* rename migrations

* core: render channel preview data

* core: render channel preview data in relays

* website: use cpp to inject JS functions

* JSC files

* remove directory.js

* channel preview renderer

* Revert "cli: fix redraw slowness (#6735)"

This reverts commit b801d77c74.

* sample channel page

* default avatar

* rename options

* better layout

* layout

* images

* some fixes

* tails

* markdown colors

* image sizes

* reactions

* fix reactions

* fewer avatars

* forward icon

* command to change group access parameters

* view public group access changes in CLI

* media metadata color

* ios: group web access ui

* update ui

* add init

* kotlin, labels

* update page

* update relay base URL

* fix

* ios update channel web page info

* update kotlin layout

* use cards

* update layout

* use domains for relay data, path is fixed

* update embed code

* fix bots api

* include only history items and senders

* update preview JS/HTML

* show different error if link is different

* remove stale json files

* better layout

* layout fixes

* improve layout

* improve layout

* update embed code

* web cta

* better layout

* buttons

* layout

* paddings

* desktop cta

* desktop cta

* cta layout

* fonts

* paddings

* paddings

* more paddings

* copy link

* read more

* hide avatar and placeholder when all messages are from channel

* color scheme

* fix color

* improve

* layout

* welcome message

* dark mode colors

* padding

* font size

* overscroll

* font

* logo on button

* better join

* buttons

* refactor

* another logo

* text

* desktop button

* button text

* center

* fix svg

* padding

* smaller gap

* render channel on any message changes etc

* fixes

* atomic file updates, escape attributes

* fix tests

* more tests

* more efficient rendering

* improve security

* sanitize links, include mentioned members

* schema

* fixes

* improve rendering

* fix showing correct subscribers count

* fix member names

---------

Co-authored-by: Evgeny @ SimpleX Chat <259188159+evgeny-simplex@users.noreply.github.com>
This commit is contained in:
Evgeny
2026-06-16 14:36:55 +01:00
committed by GitHub
co-authored by Evgeny @ SimpleX Chat
parent 43904dd0dc
commit adb3fb8cb2
42 changed files with 3234 additions and 175 deletions
+39
View File
@@ -67,6 +67,7 @@ module Simplex.Chat.Store.Groups
getGroupMembersByIndexes,
getSupportScopeMembersByIndexes,
getGroupModerators,
getGroupOwners,
getGroupRelayMembers,
getGroupMembersForExpiration,
getRemovedMembersToCleanup,
@@ -98,9 +99,12 @@ module Simplex.Chat.Store.Groups
createRelayRequestGroup,
updateRelayOwnStatusFromTo,
updateRelayOwnStatus_,
getRelaySentWebDomain,
updateRelaySentWebDomain,
isRelayGroupRejected,
allowRelayGroup,
getRelayServedGroups,
getRelayPublishableGroups,
getRelayInactiveGroups,
createNewContactMemberAsync,
createJoiningMember,
@@ -1211,6 +1215,15 @@ getGroupModerators db cxt user@User {userId, userContactId} GroupInfo {groupId}
(groupMemberQuery <> " WHERE m.user_id = ? AND m.group_id = ? AND (m.contact_id IS NULL OR m.contact_id != ?) AND m.member_role IN (?,?,?)")
(userId, groupId, userContactId, GRModerator, GRAdmin, GROwner)
getGroupOwners :: DB.Connection -> StoreCxt -> User -> GroupInfo -> IO [GroupMember]
getGroupOwners db cxt user@User {userId, userContactId} GroupInfo {groupId} = do
ts <- getCurrentTime
map (toContactMember ts cxt user)
<$> DB.query
db
(groupMemberQuery <> " WHERE m.user_id = ? AND m.group_id = ? AND (m.contact_id IS NULL OR m.contact_id != ?) AND m.member_role = ?")
(userId, groupId, userContactId, GROwner)
getGroupRelayMembers :: DB.Connection -> StoreCxt -> User -> GroupInfo -> IO [GroupMember]
getGroupRelayMembers db cxt user@User {userId, userContactId} GroupInfo {groupId} = do
currentTs <- getCurrentTime
@@ -1650,6 +1663,14 @@ updateRelayOwnStatus_ db GroupInfo {groupId} relayStatus = do
let inactiveAt_ = if relayStatus == RSInactive then Just currentTs else Nothing
DB.execute db "UPDATE groups SET relay_own_status = ?, relay_inactive_at = ?, updated_at = ? WHERE group_id = ?" (relayStatus, inactiveAt_, currentTs, groupId)
getRelaySentWebDomain :: DB.Connection -> GroupInfo -> IO (Maybe Text)
getRelaySentWebDomain db GroupInfo {groupId} =
join <$> maybeFirstRow fromOnly (DB.query db "SELECT relay_sent_web_domain FROM groups WHERE group_id = ?" (Only groupId))
updateRelaySentWebDomain :: DB.Connection -> GroupInfo -> Maybe Text -> IO ()
updateRelaySentWebDomain db GroupInfo {groupId} webDomain_ =
DB.execute db "UPDATE groups SET relay_sent_web_domain = ? WHERE group_id = ?" (webDomain_, groupId)
-- Flip every RSRejected row sharing the targeted group's relay_request_group_link
-- to RSInactive in one statement; returns the refreshed GroupInfo for the targeted groupId.
allowRelayGroup :: DB.Connection -> StoreCxt -> User -> GroupId -> ExceptT StoreError IO GroupInfo
@@ -1696,6 +1717,24 @@ getRelayServedGroups db cxt User {userId, userContactId} = do
)
(userId, userContactId, RSAccepted, RSActive)
getRelayPublishableGroups :: DB.Connection -> User -> IO [(Int64, B64UrlByteString, Maybe PublicGroupAccess)]
getRelayPublishableGroups db User {userId, userContactId} =
map toRow <$>
DB.query
db
[sql|
SELECT g.group_id, gp.public_group_id,
gp.group_web_page, gp.group_domain, gp.domain_web_page, gp.allow_embedding
FROM groups g
JOIN group_profiles gp ON gp.group_profile_id = g.group_profile_id
JOIN group_members mu ON mu.group_id = g.group_id AND mu.contact_id = ?
WHERE g.user_id = ? AND g.relay_own_status IN (?, ?)
AND gp.public_group_id IS NOT NULL
|]
(userContactId, userId, RSAccepted, RSActive)
where
toRow ((gId, pgId) :. accessRow) = (gId, pgId, toPublicGroupAccess accessRow)
getRelayInactiveGroups :: DB.Connection -> StoreCxt -> User -> NominalDiffTime -> IO [GroupInfo]
getRelayInactiveGroups db cxt User {userId, userContactId} ttl = do
currentTs <- getCurrentTime