mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-06-04 21:12:05 +00:00
rfc: namespace (#7001)
* rfc: namespace * update rfc * markdown for names * record type, app "upgrade" alerts * update api types * rfc: change namespace syntax - now it is the usual namespace * update bot types * move types to simplexmq * core: refactore markdown * update simplexmq * better names * new names * update nix content hashes * fix * change valid name function * update simplexq, update valid name conditions * fixes Co-authored-by: simplex-chat-agent[bot] <287173099+simplex-chat-agent[bot]@users.noreply.github.com> * update simplexmq * fix localization * simpler * refactor * refactor * fix --------- Co-authored-by: Evgeny @ SimpleX Chat <259188159+evgeny-simplex@users.noreply.github.com> Co-authored-by: simplex-chat-agent[bot] <287173099+simplex-chat-agent[bot]@users.noreply.github.com>
This commit is contained in:
@@ -5547,17 +5547,25 @@ mkValidName :: String -> String
|
||||
mkValidName = dropWhileEnd isSpace . take 50 . reverse . fst3 . foldl' addChar ("", '\NUL', 0 :: Int)
|
||||
where
|
||||
fst3 (x, _, _) = x
|
||||
addChar (r, prev, punct) c = if validChar then (c' : r, c', punct') else (r, prev, punct)
|
||||
addChar (r, prev, punct) c' = if validChar then (c : r, c, punct') else (r, prev, punct)
|
||||
where
|
||||
c' = if isSpace c then ' ' else c
|
||||
c = if isSpace c' then ' ' else c'
|
||||
cat = generalCategory c
|
||||
isPunct = case cat of
|
||||
ConnectorPunctuation -> True
|
||||
DashPunctuation -> True
|
||||
OtherPunctuation -> True
|
||||
_ -> False
|
||||
punct'
|
||||
| isPunctuation c = punct + 1
|
||||
| isSpace c = punct
|
||||
| isPunct = punct + 1
|
||||
| c == ' ' = punct
|
||||
| otherwise = 0
|
||||
validChar
|
||||
| c == '\'' = False
|
||||
| prev == '\NUL' = c > ' ' && c /= '#' && c /= '@' && validFirstChar
|
||||
| isSpace prev = validFirstChar || (punct == 0 && isPunctuation c)
|
||||
| isPunctuation prev = validFirstChar || isSpace c || (punct < 3 && isPunctuation c)
|
||||
| otherwise = validFirstChar || isSpace c || isMark c || isPunctuation c
|
||||
validFirstChar = isLetter c || isNumber c || isSymbol c
|
||||
| c `elem` prohibited = False
|
||||
| prev == '\NUL' = c > ' ' && validFirstNameChar
|
||||
| prev == ' ' = validFirstChar || (punct == 0 && isPunct)
|
||||
| punct > 0 = validFirstChar || c == ' '
|
||||
| otherwise = validFirstChar || c == ' ' || isMark c || isPunct
|
||||
validFirstNameChar = isLetter c || cat == DecimalNumber || cat == OtherSymbol
|
||||
validFirstChar = validFirstNameChar || cat == CurrencySymbol || cat == MathSymbol
|
||||
prohibited = ".,;/\\#@'\"`~" :: String
|
||||
|
||||
@@ -35,11 +35,11 @@ import Data.Text (Text)
|
||||
import qualified Data.Text as T
|
||||
import Data.Text.Encoding (encodeUtf8)
|
||||
import Simplex.Chat.Types
|
||||
import Simplex.Messaging.Agent.Protocol (AConnectionLink (..), ConnReqUriData (..), ConnShortLink (..), ConnectionLink (..), ConnectionRequestUri (..), ContactConnType (..), SMPQueue (..), simplexConnReqUri, simplexShortLink)
|
||||
import Simplex.Messaging.Agent.Protocol (AConnectionLink (..), ConnReqUriData (..), ConnShortLink (..), ConnectionLink (..), ConnectionRequestUri (..), ContactConnType (..), SMPQueue (..), SimplexNameInfo (..), simplexConnReqUri, simplexShortLink)
|
||||
import Simplex.Messaging.Encoding.String
|
||||
import Simplex.Messaging.Parsers (defaultJSON, dropPrefix, enumJSON, fstToLower, sumTypeJSON)
|
||||
import Simplex.Messaging.Protocol (ProtocolServer (..))
|
||||
import Simplex.Messaging.Util (decodeJSON, safeDecodeUtf8, tshow)
|
||||
import Simplex.Messaging.Util (decodeJSON, safeDecodeUtf8, tshow, (<$?>))
|
||||
import System.Console.ANSI.Types
|
||||
import qualified Text.Email.Validate as Email
|
||||
import qualified URI.ByteString as U
|
||||
@@ -59,6 +59,7 @@ data Format
|
||||
-- showText is Nothing for the usual Uri without text
|
||||
| HyperLink {showText :: Maybe Text, linkUri :: Text}
|
||||
| SimplexLink {showText :: Maybe Text, linkType :: SimplexLinkType, simplexUri :: AConnectionLink, smpHosts :: NonEmpty Text}
|
||||
| SimplexName {nameInfo :: SimplexNameInfo}
|
||||
| Command {commandStr :: Text}
|
||||
| Mention {memberName :: Text}
|
||||
| Email
|
||||
@@ -184,6 +185,7 @@ isLink = \case
|
||||
Uri -> True
|
||||
HyperLink {} -> True
|
||||
SimplexLink {} -> True
|
||||
SimplexName {} -> True
|
||||
_ -> False
|
||||
|
||||
hasLinks :: MarkdownList -> Bool
|
||||
@@ -202,9 +204,9 @@ markdownP = mconcat <$> A.many' fragmentP
|
||||
'_' -> formattedP '_' Italic
|
||||
'~' -> formattedP '~' StrikeThrough
|
||||
'`' -> formattedP '`' Snippet
|
||||
'#' -> A.char '#' *> secretP
|
||||
'#' -> A.char '#' *> (secretP <|> nameRefP '#' <|> secretFallback)
|
||||
'!' -> styledP <|> wordP
|
||||
'@' -> mentionP <|> wordP
|
||||
'@' -> (A.char '@' *> nameRefP '@') <|> mentionP <|> wordP
|
||||
'/' -> commandP <|> wordP
|
||||
'[' -> sowLinkP <|> wordP
|
||||
_
|
||||
@@ -221,14 +223,29 @@ markdownP = mconcat <$> A.many' fragmentP
|
||||
unmarked $ c `T.cons` s `T.snoc` c
|
||||
| otherwise = markdown f s
|
||||
secretP :: Parser Markdown
|
||||
secretP = secret <$> A.takeWhile (== '#') <*> A.takeTill (== '#') <*> A.takeWhile (== '#')
|
||||
secret :: Text -> Text -> Text -> Markdown
|
||||
secret b s a
|
||||
| T.null a || T.null s || T.head s == ' ' || T.last s == ' ' =
|
||||
unmarked $ '#' `T.cons` ss
|
||||
| otherwise = markdown Secret $ T.init ss
|
||||
secretP = secret <$?> ((,,) <$> A.takeWhile (== '#') <*> A.takeTill (== '#') <*> A.takeWhile1 (== '#'))
|
||||
secret :: (Text, Text, Text) -> Either String Markdown
|
||||
secret (b, s, a)
|
||||
| T.null s || T.head s == ' ' || T.last s == ' ' = Left "not secret"
|
||||
| otherwise = Right $ markdown Secret $ T.init ss
|
||||
where
|
||||
ss = b <> s <> a
|
||||
secretFallback :: Parser Markdown
|
||||
secretFallback = unmarked . ('#' `T.cons`) <$> A.takeTill (== ' ')
|
||||
nameRefP :: Char -> Parser Markdown
|
||||
nameRefP pfx = nameRef <$?> A.takeTill (== ' ')
|
||||
where
|
||||
nameRef word
|
||||
| pfx == '@' && T.all (/= '.') name = Left "not a name"
|
||||
| otherwise = mkMd <$> strDecode (encodeUtf8 full)
|
||||
where
|
||||
(name, punct) = splitPunctuation word
|
||||
full = pfx `T.cons` name
|
||||
mkMd ni
|
||||
| T.null punct = md'
|
||||
| otherwise = md' :|: unmarked punct
|
||||
where
|
||||
md' = markdown (SimplexName ni) full
|
||||
styledP :: Parser Markdown
|
||||
styledP = do
|
||||
f <- A.char '!' *> ((A.char '-' $> Small) <|> (colored <$> colorP)) <* A.space
|
||||
@@ -449,6 +466,7 @@ markdownText (FormattedText f_ t) = case f_ of
|
||||
Uri -> t
|
||||
HyperLink {} -> t
|
||||
SimplexLink {} -> t
|
||||
SimplexName {} -> t
|
||||
Mention _ -> t
|
||||
Command _ -> t
|
||||
Email -> t
|
||||
@@ -479,7 +497,6 @@ displayNameTextP_ = (,"") <$> quoted '\'' <|> splitPunctuation <$> takeNameTill
|
||||
takeNameTill p =
|
||||
A.peekChar' >>= \c ->
|
||||
if refChar c then A.takeTill p else fail "invalid first character in display name"
|
||||
splitPunctuation s = (T.dropWhileEnd isPunctuation s, T.takeWhileEnd isPunctuation s)
|
||||
quoted c = A.char c *> takeNameTill (== c) <* A.char c
|
||||
refChar c = c > ' ' && c /= '#' && c /= '@' && c /= '\''
|
||||
|
||||
@@ -490,6 +507,9 @@ commandTextP = do
|
||||
(keyword : _) | T.all (\c -> isAlpha c || isDigit c || c == '_') keyword -> pure (cmd, punct)
|
||||
_ -> fail "invalid command keyword"
|
||||
|
||||
splitPunctuation :: Text -> (Text, Text)
|
||||
splitPunctuation s = (T.dropWhileEnd isPunctuation s, T.takeWhileEnd isPunctuation s)
|
||||
|
||||
-- quotes names that contain spaces or end on punctuation
|
||||
viewName :: Text -> Text
|
||||
viewName s = if T.any isSpace s || maybe False (isPunctuation . snd) (T.unsnoc s) then "'" <> s <> "'" else s
|
||||
|
||||
@@ -3969,6 +3969,15 @@ Query:
|
||||
Plan:
|
||||
SEARCH chat_items USING INDEX idx_chat_items_group_shared_msg_id (user_id=? AND group_id=? AND group_member_id=?)
|
||||
|
||||
Query:
|
||||
UPDATE chat_items
|
||||
SET item_deleted = ?, item_deleted_ts = ?, item_deleted_by_group_member_id = ?, updated_at = ?
|
||||
WHERE user_id = ? AND group_id = ? AND msg_content_tag = ? AND item_deleted = ? AND item_sent = 0
|
||||
RETURNING chat_item_id
|
||||
|
||||
Plan:
|
||||
SEARCH chat_items USING COVERING INDEX idx_chat_items_groups_msg_content_tag_deleted (user_id=? AND group_id=? AND msg_content_tag=? AND item_deleted=? AND item_sent=?)
|
||||
|
||||
Query:
|
||||
UPDATE chat_items
|
||||
SET item_deleted = ?, item_deleted_ts = ?, item_deleted_by_group_member_id = ?, updated_at = ?
|
||||
@@ -6870,6 +6879,10 @@ Query: SELECT member_status FROM group_members WHERE local_display_name = ?
|
||||
Plan:
|
||||
SCAN group_members
|
||||
|
||||
Query: SELECT member_status FROM group_members WHERE member_role = 'relay'
|
||||
Plan:
|
||||
SCAN group_members
|
||||
|
||||
Query: SELECT member_xcontact_id, member_welcome_shared_msg_id FROM group_members WHERE user_id = ? AND group_id = ? AND group_member_id = ?
|
||||
Plan:
|
||||
SEARCH group_members USING INTEGER PRIMARY KEY (rowid=?)
|
||||
|
||||
Reference in New Issue
Block a user