mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-08-28 07:34:16 +00:00
core, ui: short bio/description for contact and group profiles (#6055)
* core: short bio/description for contact and group profiles * use short description in commands * fix tests * query plans * ios: show contact and group profile descriptions * android, desktop: short description/bio * ui: layout for chat info, correct copy * comment out fields to add/edit short descriptions * remove short description from events * postgres schema
This commit is contained in:
@@ -111,7 +111,7 @@ struct ChatInfoView: View {
|
||||
@State private var sendReceiptsUserDefault = true
|
||||
@State private var progressIndicator = false
|
||||
@AppStorage(DEFAULT_DEVELOPER_TOOLS) private var developerTools = false
|
||||
|
||||
|
||||
enum ChatInfoViewAlert: Identifiable {
|
||||
case clearChatAlert
|
||||
case networkStatusAlert
|
||||
@@ -135,7 +135,7 @@ struct ChatInfoView: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var body: some View {
|
||||
NavigationView {
|
||||
ZStack {
|
||||
@@ -146,12 +146,12 @@ struct ChatInfoView: View {
|
||||
.onTapGesture {
|
||||
aliasTextFieldFocused = false
|
||||
}
|
||||
|
||||
|
||||
localAliasTextEdit()
|
||||
.listRowBackground(Color.clear)
|
||||
.listRowSeparator(.hidden)
|
||||
.padding(.bottom, 18)
|
||||
|
||||
|
||||
GeometryReader { g in
|
||||
HStack(alignment: .center, spacing: 8) {
|
||||
let buttonWidth = g.size.width / 4
|
||||
@@ -169,7 +169,7 @@ struct ChatInfoView: View {
|
||||
.listRowBackground(Color.clear)
|
||||
.listRowSeparator(.hidden)
|
||||
.listRowInsets(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 8))
|
||||
|
||||
|
||||
if let customUserProfile = customUserProfile {
|
||||
Section(header: Text("Incognito").foregroundColor(theme.colors.secondary)) {
|
||||
HStack {
|
||||
@@ -180,7 +180,7 @@ struct ChatInfoView: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Section {
|
||||
if let code = connectionCode { verifyCodeButton(code) }
|
||||
contactPreferencesButton()
|
||||
@@ -203,19 +203,19 @@ struct ChatInfoView: View {
|
||||
// }
|
||||
}
|
||||
.disabled(!contact.ready || !contact.active)
|
||||
|
||||
|
||||
Section {
|
||||
ChatTTLOption(chat: chat, progressIndicator: $progressIndicator)
|
||||
} footer: {
|
||||
Text("Delete chat messages from your device.")
|
||||
}
|
||||
|
||||
|
||||
if let conn = contact.activeConn {
|
||||
Section {
|
||||
infoRow(Text(String("E2E encryption")), conn.connPQEnabled ? "Quantum resistant" : "Standard")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if let contactLink = contact.contactLink {
|
||||
Section {
|
||||
SimpleXLinkQRCode(uri: contactLink)
|
||||
@@ -232,7 +232,7 @@ struct ChatInfoView: View {
|
||||
.foregroundColor(theme.colors.secondary)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if contact.ready && contact.active {
|
||||
Section(header: Text("Servers").foregroundColor(theme.colors.secondary)) {
|
||||
networkStatusRow()
|
||||
@@ -261,12 +261,12 @@ struct ChatInfoView: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Section {
|
||||
clearChatButton()
|
||||
deleteContactButton()
|
||||
}
|
||||
|
||||
|
||||
if developerTools {
|
||||
Section(header: Text("For console").foregroundColor(theme.colors.secondary)) {
|
||||
infoRow("Local name", chat.chatInfo.localDisplayName)
|
||||
@@ -291,7 +291,7 @@ struct ChatInfoView: View {
|
||||
.navigationBarHidden(true)
|
||||
.disabled(progressIndicator)
|
||||
.opacity(progressIndicator ? 0.6 : 1)
|
||||
|
||||
|
||||
if progressIndicator {
|
||||
ProgressView().scaleEffect(2)
|
||||
}
|
||||
@@ -303,7 +303,7 @@ struct ChatInfoView: View {
|
||||
sendReceiptsUserDefault = currentUser.sendRcptsContacts
|
||||
}
|
||||
sendReceipts = SendReceipts.fromBool(contact.chatSettings.sendRcpts, userDefault: sendReceiptsUserDefault)
|
||||
|
||||
|
||||
Task {
|
||||
do {
|
||||
let (stats, profile) = try await apiContactInfo(chat.chatInfo.apiId)
|
||||
@@ -342,7 +342,7 @@ struct ChatInfoView: View {
|
||||
}
|
||||
}
|
||||
.actionSheet(item: $actionSheet) { $0.actionSheet }
|
||||
.sheet(item: $sheet) {
|
||||
.sheet(item: $sheet) {
|
||||
if #available(iOS 16.0, *) {
|
||||
$0.content
|
||||
.presentationDetents([.fraction($0.fraction)])
|
||||
@@ -361,41 +361,51 @@ struct ChatInfoView: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private func contactInfoHeader() -> some View {
|
||||
VStack(spacing: 8) {
|
||||
let cInfo = chat.chatInfo
|
||||
ChatInfoImage(chat: chat, size: 192, color: Color(uiColor: .tertiarySystemFill))
|
||||
.padding(.vertical, 12)
|
||||
// show actual display name, alias can be edited in this view
|
||||
let displayName = contact.profile.displayName.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
let fullName = cInfo.fullName.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
if contact.verified {
|
||||
(
|
||||
Text(Image(systemName: "checkmark.shield"))
|
||||
.foregroundColor(theme.colors.secondary)
|
||||
.font(.title2)
|
||||
+ textSpace
|
||||
+ Text(contact.profile.displayName)
|
||||
+ Text(displayName)
|
||||
.font(.largeTitle)
|
||||
)
|
||||
.multilineTextAlignment(.center)
|
||||
.lineLimit(2)
|
||||
.padding(.bottom, 2)
|
||||
} else {
|
||||
Text(contact.profile.displayName)
|
||||
Text(displayName)
|
||||
.font(.largeTitle)
|
||||
.multilineTextAlignment(.center)
|
||||
.lineLimit(2)
|
||||
.padding(.bottom, 2)
|
||||
}
|
||||
if cInfo.fullName != "" && cInfo.fullName != cInfo.displayName && cInfo.fullName != contact.profile.displayName {
|
||||
if fullName != "" && fullName != displayName && fullName != cInfo.displayName.trimmingCharacters(in: .whitespacesAndNewlines) {
|
||||
Text(cInfo.fullName)
|
||||
.font(.title2)
|
||||
.multilineTextAlignment(.center)
|
||||
.lineLimit(3)
|
||||
.padding(.bottom, 2)
|
||||
}
|
||||
if let descr = cInfo.shortDescr?.trimmingCharacters(in: .whitespacesAndNewlines), descr != "" {
|
||||
Text(descr)
|
||||
.font(.subheadline)
|
||||
.multilineTextAlignment(.center)
|
||||
.lineLimit(4)
|
||||
}
|
||||
}
|
||||
.frame(maxWidth: .infinity, alignment: .center)
|
||||
}
|
||||
|
||||
|
||||
private func localAliasTextEdit() -> some View {
|
||||
TextField("Set contact name…", text: $localAlias)
|
||||
.disableAutocorrection(true)
|
||||
@@ -412,7 +422,7 @@ struct ChatInfoView: View {
|
||||
.multilineTextAlignment(.center)
|
||||
.foregroundColor(theme.colors.secondary)
|
||||
}
|
||||
|
||||
|
||||
private func setContactAlias() {
|
||||
Task {
|
||||
do {
|
||||
@@ -475,7 +485,7 @@ struct ChatInfoView: View {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private func contactPreferencesButton() -> some View {
|
||||
NavigationLink {
|
||||
ContactPreferencesView(
|
||||
@@ -491,7 +501,7 @@ struct ChatInfoView: View {
|
||||
Label("Contact preferences", systemImage: "switch.2")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private func sendReceiptsOption() -> some View {
|
||||
WrappedPicker(selection: $sendReceipts) {
|
||||
ForEach([.yes, .no, .userDefault(sendReceiptsUserDefault)]) { (opt: SendReceipts) in
|
||||
@@ -504,7 +514,7 @@ struct ChatInfoView: View {
|
||||
setSendReceipts()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private func setSendReceipts() {
|
||||
var chatSettings = chat.chatInfo.chatSettings ?? ChatSettings.defaults
|
||||
chatSettings.sendRcpts = sendReceipts.bool()
|
||||
@@ -524,7 +534,7 @@ struct ChatInfoView: View {
|
||||
.foregroundColor(.orange)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private func synchronizeConnectionButtonForce() -> some View {
|
||||
Button {
|
||||
alert = .syncConnectionForceAlert
|
||||
@@ -533,7 +543,7 @@ struct ChatInfoView: View {
|
||||
.foregroundColor(.red)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private func networkStatusRow() -> some View {
|
||||
HStack {
|
||||
Text("Network status")
|
||||
@@ -546,14 +556,14 @@ struct ChatInfoView: View {
|
||||
serverImage()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private func serverImage() -> some View {
|
||||
let status = networkModel.contactNetworkStatus(contact)
|
||||
return Image(systemName: status.imageName)
|
||||
.foregroundColor(status == .connected ? .green : theme.colors.secondary)
|
||||
.font(.system(size: 12))
|
||||
}
|
||||
|
||||
|
||||
private func deleteContactButton() -> some View {
|
||||
Button(role: .destructive) {
|
||||
deleteContactDialog(
|
||||
@@ -569,7 +579,7 @@ struct ChatInfoView: View {
|
||||
.foregroundColor(Color.red)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private func clearChatButton() -> some View {
|
||||
Button() {
|
||||
alert = .clearChatAlert
|
||||
@@ -578,7 +588,7 @@ struct ChatInfoView: View {
|
||||
.foregroundColor(Color.orange)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private func clearChatAlert() -> Alert {
|
||||
Alert(
|
||||
title: Text("Clear conversation?"),
|
||||
@@ -592,14 +602,14 @@ struct ChatInfoView: View {
|
||||
secondaryButton: .cancel()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
private func networkStatusAlert() -> Alert {
|
||||
Alert(
|
||||
title: Text("Network status"),
|
||||
message: Text(networkModel.contactNetworkStatus(contact).statusExplanation)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
private func switchContactAddress() {
|
||||
Task {
|
||||
do {
|
||||
@@ -618,7 +628,7 @@ struct ChatInfoView: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private func abortSwitchContactAddress() {
|
||||
Task {
|
||||
do {
|
||||
@@ -636,7 +646,7 @@ struct ChatInfoView: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private func savePreferences() {
|
||||
Task {
|
||||
do {
|
||||
@@ -668,7 +678,7 @@ struct ChatTTLOption: View {
|
||||
}
|
||||
let defaultTTL = ChatTTL.userDefault(ChatModel.shared.chatItemTTL)
|
||||
Text(defaultTTL.text).tag(defaultTTL)
|
||||
|
||||
|
||||
if case .chat(let ttl) = chatItemTTL, case .seconds = ttl {
|
||||
Text(ttl.deleteAfterText).tag(chatItemTTL)
|
||||
}
|
||||
@@ -1136,13 +1146,13 @@ func setChatTTL(_ ttl: ChatTTL, hasPreviousTTL: Bool, onCancel: @escaping () ->
|
||||
} else {
|
||||
NSLocalizedString("Enable automatic message deletion?", comment: "alert title")
|
||||
}
|
||||
|
||||
|
||||
let message = if ttl.neverExpires {
|
||||
NSLocalizedString("Messages in this chat will never be deleted.", comment: "alert message")
|
||||
} else {
|
||||
NSLocalizedString("This action cannot be undone - the messages sent and received in this chat earlier than selected will be deleted.", comment: "alert message")
|
||||
}
|
||||
|
||||
|
||||
showAlert(title, message: message) {
|
||||
[
|
||||
UIAlertAction(
|
||||
|
||||
@@ -75,12 +75,12 @@ struct GroupChatInfoView: View {
|
||||
List {
|
||||
groupInfoHeader()
|
||||
.listRowBackground(Color.clear)
|
||||
|
||||
|
||||
localAliasTextEdit()
|
||||
.listRowBackground(Color.clear)
|
||||
.listRowSeparator(.hidden)
|
||||
.padding(.bottom, 18)
|
||||
|
||||
|
||||
infoActionButtons()
|
||||
.padding(.horizontal)
|
||||
.frame(maxWidth: .infinity)
|
||||
@@ -124,7 +124,7 @@ struct GroupChatInfoView: View {
|
||||
Text(label)
|
||||
.foregroundColor(theme.colors.secondary)
|
||||
}
|
||||
|
||||
|
||||
Section {
|
||||
if members.filter({ $0.wrapped.memberCurrent }).count <= SMALL_GROUPS_RCPS_MEM_LIMIT {
|
||||
sendReceiptsOption()
|
||||
@@ -181,7 +181,7 @@ struct GroupChatInfoView: View {
|
||||
leaveGroupButton()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if developerTools {
|
||||
Section(header: Text("For console").foregroundColor(theme.colors.secondary)) {
|
||||
infoRow("Local name", chat.chatInfo.localDisplayName)
|
||||
@@ -193,7 +193,7 @@ struct GroupChatInfoView: View {
|
||||
.navigationBarHidden(true)
|
||||
.disabled(progressIndicator)
|
||||
.opacity(progressIndicator ? 0.6 : 1)
|
||||
|
||||
|
||||
if progressIndicator {
|
||||
ProgressView().scaleEffect(2)
|
||||
}
|
||||
@@ -234,19 +234,29 @@ struct GroupChatInfoView: View {
|
||||
private func groupInfoHeader() -> some View {
|
||||
VStack {
|
||||
let cInfo = chat.chatInfo
|
||||
// show actual display name, alias can be edited in this view
|
||||
let displayName = (cInfo.groupInfo?.groupProfile.displayName ?? cInfo.displayName).trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
let fullName = cInfo.fullName.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
ChatInfoImage(chat: chat, size: 192, color: Color(uiColor: .tertiarySystemFill))
|
||||
.padding(.top, 12)
|
||||
.padding()
|
||||
Text(cInfo.groupInfo?.groupProfile.displayName ?? cInfo.displayName)
|
||||
Text(displayName)
|
||||
.font(.largeTitle)
|
||||
.multilineTextAlignment(.center)
|
||||
.lineLimit(4)
|
||||
.padding(.bottom, 2)
|
||||
if cInfo.fullName != "" && cInfo.fullName != cInfo.displayName {
|
||||
if fullName != "" && fullName != displayName && fullName != cInfo.displayName.trimmingCharacters(in: .whitespacesAndNewlines) {
|
||||
Text(cInfo.fullName)
|
||||
.font(.title2)
|
||||
.multilineTextAlignment(.center)
|
||||
.lineLimit(8)
|
||||
.lineLimit(3)
|
||||
.padding(.bottom, 2)
|
||||
}
|
||||
if let descr = cInfo.shortDescr?.trimmingCharacters(in: .whitespacesAndNewlines), descr != "" {
|
||||
Text(descr)
|
||||
.font(.subheadline)
|
||||
.multilineTextAlignment(.center)
|
||||
.lineLimit(4)
|
||||
}
|
||||
}
|
||||
.frame(maxWidth: .infinity, alignment: .center)
|
||||
@@ -268,7 +278,7 @@ struct GroupChatInfoView: View {
|
||||
.multilineTextAlignment(.center)
|
||||
.foregroundColor(theme.colors.secondary)
|
||||
}
|
||||
|
||||
|
||||
private func setGroupAlias() {
|
||||
Task {
|
||||
do {
|
||||
@@ -282,7 +292,7 @@ struct GroupChatInfoView: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func infoActionButtons() -> some View {
|
||||
GeometryReader { g in
|
||||
let buttonWidth = g.size.width / 4
|
||||
@@ -829,11 +839,11 @@ struct GroupPreferencesButton: View {
|
||||
@State var preferences: FullGroupPreferences
|
||||
@State var currentPreferences: FullGroupPreferences
|
||||
var creatingGroup: Bool = false
|
||||
|
||||
|
||||
private var label: LocalizedStringKey {
|
||||
groupInfo.businessChat == nil ? "Group preferences" : "Chat preferences"
|
||||
}
|
||||
|
||||
|
||||
var body: some View {
|
||||
NavigationLink {
|
||||
GroupPreferencesView(
|
||||
@@ -851,7 +861,7 @@ struct GroupPreferencesButton: View {
|
||||
creatingGroup ? "Save" : "Save and notify group members",
|
||||
comment: "alert button"
|
||||
)
|
||||
|
||||
|
||||
if groupInfo.fullGroupPreferences != preferences {
|
||||
showAlert(
|
||||
title: NSLocalizedString("Save preferences?", comment: "alert title"),
|
||||
@@ -869,7 +879,7 @@ struct GroupPreferencesButton: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private func savePreferences() {
|
||||
Task {
|
||||
do {
|
||||
|
||||
@@ -444,29 +444,39 @@ struct GroupMemberInfoView: View {
|
||||
MemberProfileImage(mem, size: 192, color: Color(uiColor: .tertiarySystemFill))
|
||||
.padding(.top, 12)
|
||||
.padding()
|
||||
// show alias if set, alias cannot be edited in this view
|
||||
let displayName = mem.displayName.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
let fullName = mem.fullName.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
if mem.verified {
|
||||
(
|
||||
Text(Image(systemName: "checkmark.shield"))
|
||||
.foregroundColor(theme.colors.secondary)
|
||||
.font(.title2)
|
||||
+ textSpace
|
||||
+ Text(mem.displayName)
|
||||
+ Text(displayName)
|
||||
.font(.largeTitle)
|
||||
)
|
||||
.multilineTextAlignment(.center)
|
||||
.lineLimit(2)
|
||||
.padding(.bottom, 2)
|
||||
} else {
|
||||
Text(mem.displayName)
|
||||
Text(displayName)
|
||||
.font(.largeTitle)
|
||||
.multilineTextAlignment(.center)
|
||||
.lineLimit(2)
|
||||
.padding(.bottom, 2)
|
||||
}
|
||||
if mem.fullName != "" && mem.fullName != mem.displayName {
|
||||
if fullName != "" && fullName != displayName && fullName != mem.memberProfile.displayName.trimmingCharacters(in: .whitespacesAndNewlines) {
|
||||
Text(mem.fullName)
|
||||
.font(.title2)
|
||||
.multilineTextAlignment(.center)
|
||||
.lineLimit(3)
|
||||
.padding(.bottom, 2)
|
||||
}
|
||||
if let descr = mem.memberProfile.shortDescr?.trimmingCharacters(in: .whitespacesAndNewlines), descr != "" {
|
||||
Text(descr)
|
||||
.font(.subheadline)
|
||||
.multilineTextAlignment(.center)
|
||||
.lineLimit(4)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,6 +55,8 @@ struct GroupProfileView: View {
|
||||
if fullName != "" && fullName != groupProfile.displayName {
|
||||
TextField("Group full name (optional)", text: $groupProfile.fullName)
|
||||
}
|
||||
// TODO enable in v6.4.1, limit to 160 characters
|
||||
// TextField("Short description", text: Binding(get: {groupProfile.shortDescr ?? ""}, set: {groupProfile.shortDescr = $0}))
|
||||
} footer: {
|
||||
Text("Group profile is stored on members' devices, not on the servers.")
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ struct CreateProfile: View {
|
||||
@Environment(\.dismiss) var dismiss
|
||||
@EnvironmentObject var theme: AppTheme
|
||||
@State private var displayName: String = ""
|
||||
@State private var profileBio: String = ""
|
||||
@FocusState private var focusDisplayName
|
||||
@State private var alert: UserProfileAlert?
|
||||
|
||||
@@ -37,6 +38,8 @@ struct CreateProfile: View {
|
||||
Section {
|
||||
TextField("Enter your name…", text: $displayName)
|
||||
.focused($focusDisplayName)
|
||||
// TODO enable in v6.4.1, limit to 160 characters
|
||||
// TextField("Bio", text: $profileBio)
|
||||
Button {
|
||||
createProfile()
|
||||
} label: {
|
||||
@@ -80,9 +83,11 @@ struct CreateProfile: View {
|
||||
|
||||
private func createProfile() {
|
||||
hideKeyboard()
|
||||
let shortDescr: String? = if profileBio.isEmpty { nil } else { profileBio }
|
||||
let profile = Profile(
|
||||
displayName: displayName.trimmingCharacters(in: .whitespaces),
|
||||
fullName: ""
|
||||
fullName: "",
|
||||
shortDescr: shortDescr
|
||||
)
|
||||
let m = ChatModel.shared
|
||||
do {
|
||||
|
||||
@@ -43,6 +43,8 @@ struct UserProfile: View {
|
||||
if let user = chatModel.currentUser, showFullName(user) {
|
||||
TextField("Full name (optional)", text: $profile.fullName)
|
||||
}
|
||||
// TODO enable in v6.4.1, limit to 160 characters
|
||||
// TextField("Bio", text: Binding(get: {profile.shortDescr ?? ""}, set: {profile.shortDescr = $0}))
|
||||
} footer: {
|
||||
Text("Your profile is stored on your device and shared only with your contacts. SimpleX servers cannot see your profile.")
|
||||
}
|
||||
|
||||
@@ -178,8 +178,8 @@
|
||||
64C3B0212A0D359700E19930 /* CustomTimePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64C3B0202A0D359700E19930 /* CustomTimePicker.swift */; };
|
||||
64C8299D2D54AEEE006B9E89 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C829982D54AEED006B9E89 /* libgmp.a */; };
|
||||
64C8299E2D54AEEE006B9E89 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C829992D54AEEE006B9E89 /* libffi.a */; };
|
||||
64C8299F2D54AEEE006B9E89 /* libHSsimplex-chat-6.4.0.5.1-Hjmcl0BGDg19a5be1DeLnp-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C8299A2D54AEEE006B9E89 /* libHSsimplex-chat-6.4.0.5.1-Hjmcl0BGDg19a5be1DeLnp-ghc9.6.3.a */; };
|
||||
64C829A02D54AEEE006B9E89 /* libHSsimplex-chat-6.4.0.5.1-Hjmcl0BGDg19a5be1DeLnp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C8299B2D54AEEE006B9E89 /* libHSsimplex-chat-6.4.0.5.1-Hjmcl0BGDg19a5be1DeLnp.a */; };
|
||||
64C8299F2D54AEEE006B9E89 /* libHSsimplex-chat-6.4.0.5.1-H9b1PUqJfdC45BY0VzYHX-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C8299A2D54AEEE006B9E89 /* libHSsimplex-chat-6.4.0.5.1-H9b1PUqJfdC45BY0VzYHX-ghc9.6.3.a */; };
|
||||
64C829A02D54AEEE006B9E89 /* libHSsimplex-chat-6.4.0.5.1-H9b1PUqJfdC45BY0VzYHX.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C8299B2D54AEEE006B9E89 /* libHSsimplex-chat-6.4.0.5.1-H9b1PUqJfdC45BY0VzYHX.a */; };
|
||||
64C829A12D54AEEE006B9E89 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C8299C2D54AEEE006B9E89 /* libgmpxx.a */; };
|
||||
64D0C2C029F9688300B38D5F /* UserAddressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64D0C2BF29F9688300B38D5F /* UserAddressView.swift */; };
|
||||
64D0C2C229FA57AB00B38D5F /* UserAddressLearnMore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64D0C2C129FA57AB00B38D5F /* UserAddressLearnMore.swift */; };
|
||||
@@ -543,8 +543,8 @@
|
||||
64C3B0202A0D359700E19930 /* CustomTimePicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomTimePicker.swift; sourceTree = "<group>"; };
|
||||
64C829982D54AEED006B9E89 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = "<group>"; };
|
||||
64C829992D54AEEE006B9E89 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = "<group>"; };
|
||||
64C8299A2D54AEEE006B9E89 /* libHSsimplex-chat-6.4.0.5.1-Hjmcl0BGDg19a5be1DeLnp-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.4.0.5.1-Hjmcl0BGDg19a5be1DeLnp-ghc9.6.3.a"; sourceTree = "<group>"; };
|
||||
64C8299B2D54AEEE006B9E89 /* libHSsimplex-chat-6.4.0.5.1-Hjmcl0BGDg19a5be1DeLnp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.4.0.5.1-Hjmcl0BGDg19a5be1DeLnp.a"; sourceTree = "<group>"; };
|
||||
64C8299A2D54AEEE006B9E89 /* libHSsimplex-chat-6.4.0.5.1-H9b1PUqJfdC45BY0VzYHX-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.4.0.5.1-H9b1PUqJfdC45BY0VzYHX-ghc9.6.3.a"; sourceTree = "<group>"; };
|
||||
64C8299B2D54AEEE006B9E89 /* libHSsimplex-chat-6.4.0.5.1-H9b1PUqJfdC45BY0VzYHX.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.4.0.5.1-H9b1PUqJfdC45BY0VzYHX.a"; sourceTree = "<group>"; };
|
||||
64C8299C2D54AEEE006B9E89 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = "<group>"; };
|
||||
64D0C2BF29F9688300B38D5F /* UserAddressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserAddressView.swift; sourceTree = "<group>"; };
|
||||
64D0C2C129FA57AB00B38D5F /* UserAddressLearnMore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserAddressLearnMore.swift; sourceTree = "<group>"; };
|
||||
@@ -704,8 +704,8 @@
|
||||
64C8299D2D54AEEE006B9E89 /* libgmp.a in Frameworks */,
|
||||
64C8299E2D54AEEE006B9E89 /* libffi.a in Frameworks */,
|
||||
64C829A12D54AEEE006B9E89 /* libgmpxx.a in Frameworks */,
|
||||
64C8299F2D54AEEE006B9E89 /* libHSsimplex-chat-6.4.0.5.1-Hjmcl0BGDg19a5be1DeLnp-ghc9.6.3.a in Frameworks */,
|
||||
64C829A02D54AEEE006B9E89 /* libHSsimplex-chat-6.4.0.5.1-Hjmcl0BGDg19a5be1DeLnp.a in Frameworks */,
|
||||
64C8299F2D54AEEE006B9E89 /* libHSsimplex-chat-6.4.0.5.1-H9b1PUqJfdC45BY0VzYHX-ghc9.6.3.a in Frameworks */,
|
||||
64C829A02D54AEEE006B9E89 /* libHSsimplex-chat-6.4.0.5.1-H9b1PUqJfdC45BY0VzYHX.a in Frameworks */,
|
||||
CE38A29C2C3FCD72005ED185 /* SwiftyGif in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@@ -790,8 +790,8 @@
|
||||
64C829992D54AEEE006B9E89 /* libffi.a */,
|
||||
64C829982D54AEED006B9E89 /* libgmp.a */,
|
||||
64C8299C2D54AEEE006B9E89 /* libgmpxx.a */,
|
||||
64C8299A2D54AEEE006B9E89 /* libHSsimplex-chat-6.4.0.5.1-Hjmcl0BGDg19a5be1DeLnp-ghc9.6.3.a */,
|
||||
64C8299B2D54AEEE006B9E89 /* libHSsimplex-chat-6.4.0.5.1-Hjmcl0BGDg19a5be1DeLnp.a */,
|
||||
64C8299A2D54AEEE006B9E89 /* libHSsimplex-chat-6.4.0.5.1-H9b1PUqJfdC45BY0VzYHX-ghc9.6.3.a */,
|
||||
64C8299B2D54AEEE006B9E89 /* libHSsimplex-chat-6.4.0.5.1-H9b1PUqJfdC45BY0VzYHX.a */,
|
||||
);
|
||||
path = Libraries;
|
||||
sourceTree = "<group>";
|
||||
|
||||
@@ -32,6 +32,7 @@ public struct User: Identifiable, Decodable, UserLike, NamedChat, Hashable {
|
||||
|
||||
public var displayName: String { get { profile.displayName } }
|
||||
public var fullName: String { get { profile.fullName } }
|
||||
public var shortDescr: String? { profile.shortDescr }
|
||||
public var image: String? { get { profile.image } }
|
||||
public var localAlias: String { get { "" } }
|
||||
|
||||
@@ -109,12 +110,14 @@ public struct Profile: Codable, NamedChat, Hashable {
|
||||
public init(
|
||||
displayName: String,
|
||||
fullName: String,
|
||||
shortDescr: String? = nil,
|
||||
image: String? = nil,
|
||||
contactLink: String? = nil,
|
||||
preferences: Preferences? = nil
|
||||
) {
|
||||
self.displayName = displayName
|
||||
self.fullName = fullName
|
||||
self.shortDescr = shortDescr
|
||||
self.image = image
|
||||
self.contactLink = contactLink
|
||||
self.preferences = preferences
|
||||
@@ -122,6 +125,7 @@ public struct Profile: Codable, NamedChat, Hashable {
|
||||
|
||||
public var displayName: String
|
||||
public var fullName: String
|
||||
public var shortDescr: String?
|
||||
public var image: String?
|
||||
public var contactLink: String?
|
||||
public var preferences: Preferences?
|
||||
@@ -142,6 +146,7 @@ public struct LocalProfile: Codable, NamedChat, Hashable {
|
||||
profileId: Int64,
|
||||
displayName: String,
|
||||
fullName: String,
|
||||
shortDescr: String? = nil,
|
||||
image: String? = nil,
|
||||
contactLink: String? = nil,
|
||||
preferences: Preferences? = nil,
|
||||
@@ -150,6 +155,7 @@ public struct LocalProfile: Codable, NamedChat, Hashable {
|
||||
self.profileId = profileId
|
||||
self.displayName = displayName
|
||||
self.fullName = fullName
|
||||
self.shortDescr = shortDescr
|
||||
self.image = image
|
||||
self.contactLink = contactLink
|
||||
self.preferences = preferences
|
||||
@@ -159,6 +165,7 @@ public struct LocalProfile: Codable, NamedChat, Hashable {
|
||||
public var profileId: Int64
|
||||
public var displayName: String
|
||||
public var fullName: String
|
||||
public var shortDescr: String?
|
||||
public var image: String?
|
||||
public var contactLink: String?
|
||||
public var preferences: Preferences?
|
||||
@@ -180,11 +187,27 @@ public struct LocalProfile: Codable, NamedChat, Hashable {
|
||||
}
|
||||
|
||||
public func toLocalProfile (_ profileId: Int64, _ profile: Profile, _ localAlias: String) -> LocalProfile {
|
||||
LocalProfile(profileId: profileId, displayName: profile.displayName, fullName: profile.fullName, image: profile.image, contactLink: profile.contactLink, preferences: profile.preferences, localAlias: localAlias)
|
||||
LocalProfile(
|
||||
profileId: profileId,
|
||||
displayName: profile.displayName,
|
||||
fullName: profile.fullName,
|
||||
shortDescr: profile.shortDescr,
|
||||
image: profile.image,
|
||||
contactLink: profile.contactLink,
|
||||
preferences: profile.preferences,
|
||||
localAlias: localAlias
|
||||
)
|
||||
}
|
||||
|
||||
public func fromLocalProfile (_ profile: LocalProfile) -> Profile {
|
||||
Profile(displayName: profile.displayName, fullName: profile.fullName, image: profile.image, contactLink: profile.contactLink, preferences: profile.preferences)
|
||||
Profile(
|
||||
displayName: profile.displayName,
|
||||
fullName: profile.fullName,
|
||||
shortDescr: profile.shortDescr,
|
||||
image: profile.image,
|
||||
contactLink: profile.contactLink,
|
||||
preferences: profile.preferences
|
||||
)
|
||||
}
|
||||
|
||||
public struct UserProfileUpdateSummary: Decodable, Hashable {
|
||||
@@ -204,6 +227,7 @@ public enum ChatType: String, Hashable {
|
||||
public protocol NamedChat {
|
||||
var displayName: String { get }
|
||||
var fullName: String { get }
|
||||
var shortDescr: String? { get }
|
||||
var image: String? { get }
|
||||
var localAlias: String { get }
|
||||
}
|
||||
@@ -1249,6 +1273,17 @@ public enum ChatInfo: Identifiable, Decodable, NamedChat, Hashable {
|
||||
}
|
||||
}
|
||||
|
||||
public var shortDescr: String? {
|
||||
switch self {
|
||||
case let .direct(contact): contact.profile.shortDescr
|
||||
case let .group(groupInfo, _): groupInfo.groupProfile.shortDescr
|
||||
case .local: nil
|
||||
case let .contactRequest(contactRequest): contactRequest.profile.shortDescr
|
||||
case let .contactConnection(contactConnection): nil
|
||||
case .invalidJSON: nil
|
||||
}
|
||||
}
|
||||
|
||||
public var image: String? {
|
||||
get {
|
||||
switch self {
|
||||
@@ -1739,6 +1774,7 @@ public struct Contact: Identifiable, Decodable, NamedChat, Hashable {
|
||||
public var sendMsgToConnect: Bool { nextSendGrpInv || nextConnectPrepared }
|
||||
public var displayName: String { localAlias == "" ? profile.displayName : localAlias }
|
||||
public var fullName: String { get { profile.fullName } }
|
||||
public var shortDescr: String? { profile.shortDescr }
|
||||
public var image: String? { get { profile.image } }
|
||||
public var contactLink: String? { get { profile.contactLink } }
|
||||
public var localAlias: String { profile.localAlias }
|
||||
@@ -1925,6 +1961,7 @@ public struct UserContactRequest: Decodable, NamedChat, Hashable {
|
||||
public var apiId: Int64 { get { contactRequestId } }
|
||||
var ready: Bool { get { true } }
|
||||
public var displayName: String { get { profile.displayName } }
|
||||
public var shortDescr: String? { profile.shortDescr }
|
||||
public var fullName: String { get { profile.fullName } }
|
||||
public var image: String? { get { profile.image } }
|
||||
public var localAlias: String { "" }
|
||||
@@ -1977,6 +2014,7 @@ public struct PendingContactConnection: Decodable, NamedChat, Hashable {
|
||||
}
|
||||
}
|
||||
public var fullName: String { get { "" } }
|
||||
public var shortDescr: String? { nil }
|
||||
public var image: String? { get { nil } }
|
||||
public var initiated: Bool { get { (pccConnStatus.initiated ?? false) && !viaContactUri } }
|
||||
|
||||
@@ -2093,6 +2131,7 @@ public struct GroupInfo: Identifiable, Decodable, NamedChat, Hashable {
|
||||
public var profileChangeProhibited: Bool { preparedGroup?.connLinkPreparedConnection ?? false }
|
||||
public var displayName: String { localAlias == "" ? groupProfile.displayName : localAlias }
|
||||
public var fullName: String { get { groupProfile.fullName } }
|
||||
public var shortDescr: String? { groupProfile.shortDescr }
|
||||
public var image: String? { get { groupProfile.image } }
|
||||
public var chatTags: [Int64]
|
||||
public var chatItemTTL: Int64?
|
||||
@@ -2152,6 +2191,7 @@ public struct GroupProfile: Codable, NamedChat, Hashable {
|
||||
public init(
|
||||
displayName: String,
|
||||
fullName: String,
|
||||
shortDescr: String? = nil,
|
||||
description: String? = nil,
|
||||
image: String? = nil,
|
||||
groupPreferences: GroupPreferences? = nil,
|
||||
@@ -2159,6 +2199,7 @@ public struct GroupProfile: Codable, NamedChat, Hashable {
|
||||
) {
|
||||
self.displayName = displayName
|
||||
self.fullName = fullName
|
||||
self.shortDescr = shortDescr
|
||||
self.description = description
|
||||
self.image = image
|
||||
self.groupPreferences = groupPreferences
|
||||
@@ -2167,6 +2208,7 @@ public struct GroupProfile: Codable, NamedChat, Hashable {
|
||||
|
||||
public var displayName: String
|
||||
public var fullName: String
|
||||
public var shortDescr: String?
|
||||
public var description: String?
|
||||
public var image: String?
|
||||
public var groupPreferences: GroupPreferences?
|
||||
@@ -2555,6 +2597,7 @@ public struct NoteFolder: Identifiable, Decodable, NamedChat, Hashable {
|
||||
public var ready: Bool { get { true } }
|
||||
public var displayName: String { get { ChatInfo.privateNotesChatName } }
|
||||
public var fullName: String { get { "" } }
|
||||
public var shortDescr: String? { nil }
|
||||
public var image: String? { get { nil } }
|
||||
public var localAlias: String { get { "" } }
|
||||
|
||||
|
||||
+24
-4
@@ -1233,6 +1233,7 @@ data class User(
|
||||
): NamedChat, UserLike {
|
||||
override val displayName: String get() = profile.displayName
|
||||
override val fullName: String get() = profile.fullName
|
||||
override val shortDescr: String? get() = profile.shortDescr
|
||||
override val image: String? get() = profile.image
|
||||
override val localAlias: String = ""
|
||||
|
||||
@@ -1302,6 +1303,7 @@ typealias ChatId = String
|
||||
interface NamedChat {
|
||||
val displayName: String
|
||||
val fullName: String
|
||||
val shortDescr: String?
|
||||
val image: String?
|
||||
val localAlias: String
|
||||
val chatViewName: String
|
||||
@@ -1412,6 +1414,7 @@ sealed class ChatInfo: SomeChat, NamedChat {
|
||||
override val updatedAt get() = contact.updatedAt
|
||||
override val displayName get() = contact.displayName
|
||||
override val fullName get() = contact.fullName
|
||||
override val shortDescr get() = contact.profile.shortDescr
|
||||
override val image get() = contact.image
|
||||
override val localAlias: String get() = contact.localAlias
|
||||
override fun anyNameContains(searchAnyCase: String): Boolean = contact.anyNameContains(searchAnyCase)
|
||||
@@ -1439,6 +1442,7 @@ sealed class ChatInfo: SomeChat, NamedChat {
|
||||
override val updatedAt get() = groupInfo.updatedAt
|
||||
override val displayName get() = groupInfo.displayName
|
||||
override val fullName get() = groupInfo.fullName
|
||||
override val shortDescr get() = groupInfo.groupProfile.shortDescr
|
||||
override val image get() = groupInfo.image
|
||||
override val localAlias get() = groupInfo.localAlias
|
||||
|
||||
@@ -1465,6 +1469,7 @@ sealed class ChatInfo: SomeChat, NamedChat {
|
||||
override val updatedAt get() = noteFolder.updatedAt
|
||||
override val displayName get() = noteFolder.displayName
|
||||
override val fullName get() = noteFolder.fullName
|
||||
override val shortDescr get() = null
|
||||
override val image get() = noteFolder.image
|
||||
override val localAlias get() = noteFolder.localAlias
|
||||
|
||||
@@ -1491,6 +1496,7 @@ sealed class ChatInfo: SomeChat, NamedChat {
|
||||
override val updatedAt get() = contactRequest.updatedAt
|
||||
override val displayName get() = contactRequest.displayName
|
||||
override val fullName get() = contactRequest.fullName
|
||||
override val shortDescr get() = contactRequest.profile.shortDescr
|
||||
override val image get() = contactRequest.image
|
||||
override val localAlias get() = contactRequest.localAlias
|
||||
|
||||
@@ -1517,6 +1523,7 @@ sealed class ChatInfo: SomeChat, NamedChat {
|
||||
override val updatedAt get() = contactConnection.updatedAt
|
||||
override val displayName get() = contactConnection.displayName
|
||||
override val fullName get() = contactConnection.fullName
|
||||
override val shortDescr get() = null
|
||||
override val image get() = contactConnection.image
|
||||
override val localAlias get() = contactConnection.localAlias
|
||||
|
||||
@@ -1546,6 +1553,7 @@ sealed class ChatInfo: SomeChat, NamedChat {
|
||||
override val timedMessagesTTL: Int? get() = null
|
||||
override val displayName get() = invalidChatName
|
||||
override val fullName get() = invalidChatName
|
||||
override val shortDescr get() = null
|
||||
override val image get() = null
|
||||
override val localAlias get() = ""
|
||||
|
||||
@@ -1750,6 +1758,7 @@ data class Contact(
|
||||
override val timedMessagesTTL: Int? get() = with(mergedPreferences.timedMessages) { if (enabled.forUser) userPreference.pref.ttl else null }
|
||||
override val displayName get() = localAlias.ifEmpty { profile.displayName }
|
||||
override val fullName get() = profile.fullName
|
||||
override val shortDescr get() = profile.shortDescr
|
||||
override val image get() = profile.image
|
||||
val contactLink: String? = profile.contactLink
|
||||
override val localAlias get() = profile.localAlias
|
||||
@@ -1900,6 +1909,7 @@ data class SecurityCode(val securityCode: String, val verifiedAt: Instant)
|
||||
data class Profile(
|
||||
override val displayName: String,
|
||||
override val fullName: String,
|
||||
override val shortDescr: String?,
|
||||
override val image: String? = null,
|
||||
override val localAlias : String = "",
|
||||
val contactLink: String? = null,
|
||||
@@ -1910,12 +1920,13 @@ data class Profile(
|
||||
return if (fullName == "" || displayName == fullName) displayName else "$displayName ($fullName)"
|
||||
}
|
||||
|
||||
fun toLocalProfile(profileId: Long): LocalProfile = LocalProfile(profileId, displayName, fullName, image, localAlias, contactLink, preferences)
|
||||
fun toLocalProfile(profileId: Long): LocalProfile = LocalProfile(profileId, displayName, fullName, shortDescr, image, localAlias, contactLink, preferences)
|
||||
|
||||
companion object {
|
||||
val sampleData = Profile(
|
||||
displayName = "alice",
|
||||
fullName = "Alice"
|
||||
fullName = "Alice",
|
||||
shortDescr = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1925,6 +1936,7 @@ data class LocalProfile(
|
||||
val profileId: Long,
|
||||
override val displayName: String,
|
||||
override val fullName: String,
|
||||
override val shortDescr: String?,
|
||||
override val image: String? = null,
|
||||
override val localAlias: String,
|
||||
val contactLink: String? = null,
|
||||
@@ -1932,13 +1944,14 @@ data class LocalProfile(
|
||||
): NamedChat {
|
||||
val profileViewName: String = localAlias.ifEmpty { if (fullName == "" || displayName == fullName) displayName else "$displayName ($fullName)" }
|
||||
|
||||
fun toProfile(): Profile = Profile(displayName, fullName, image, localAlias, contactLink, preferences)
|
||||
fun toProfile(): Profile = Profile(displayName, fullName, shortDescr, image, localAlias, contactLink, preferences)
|
||||
|
||||
companion object {
|
||||
val sampleData = LocalProfile(
|
||||
profileId = 1L,
|
||||
displayName = "alice",
|
||||
fullName = "Alice",
|
||||
shortDescr = null,
|
||||
preferences = ChatPreferences.sampleData,
|
||||
localAlias = ""
|
||||
)
|
||||
@@ -2004,6 +2017,7 @@ data class GroupInfo (
|
||||
override val timedMessagesTTL: Int? get() = with(fullGroupPreferences.timedMessages) { if (on) ttl else null }
|
||||
override val displayName get() = localAlias.ifEmpty { groupProfile.displayName }
|
||||
override val fullName get() = groupProfile.fullName
|
||||
override val shortDescr get() = groupProfile.shortDescr
|
||||
override val image get() = groupProfile.image
|
||||
|
||||
val isOwner: Boolean
|
||||
@@ -2075,6 +2089,7 @@ data class GroupRef(val groupId: Long, val localDisplayName: String)
|
||||
data class GroupProfile (
|
||||
override val displayName: String,
|
||||
override val fullName: String,
|
||||
override val shortDescr: String?,
|
||||
val description: String? = null,
|
||||
override val image: String? = null,
|
||||
override val localAlias: String = "",
|
||||
@@ -2084,7 +2099,8 @@ data class GroupProfile (
|
||||
companion object {
|
||||
val sampleData = GroupProfile(
|
||||
displayName = "team",
|
||||
fullName = "My Team"
|
||||
fullName = "My Team",
|
||||
shortDescr = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -2169,6 +2185,7 @@ data class GroupMember (
|
||||
return pastMember(name)
|
||||
}
|
||||
override val fullName: String get() = memberProfile.fullName
|
||||
override val shortDescr: String? get() = memberProfile.shortDescr
|
||||
override val image: String? get() = memberProfile.image
|
||||
val contactLink: String? = memberProfile.contactLink
|
||||
val verified get() = activeConn?.connectionCode != null
|
||||
@@ -2453,6 +2470,7 @@ class NoteFolder(
|
||||
override val timedMessagesTTL: Int? get() = null
|
||||
override val displayName get() = generalGetString(MR.strings.note_folder_local_display_name)
|
||||
override val fullName get() = ""
|
||||
override val shortDescr get() = null
|
||||
override val image get() = null
|
||||
override val localAlias get() = ""
|
||||
override val localDisplayName: String get() = ""
|
||||
@@ -2491,6 +2509,7 @@ class UserContactRequest (
|
||||
override val timedMessagesTTL: Int? get() = null
|
||||
override val displayName get() = profile.displayName
|
||||
override val fullName get() = profile.fullName
|
||||
override val shortDescr get() = profile.shortDescr
|
||||
override val image get() = profile.image
|
||||
override val localAlias get() = ""
|
||||
|
||||
@@ -2548,6 +2567,7 @@ class PendingContactConnection(
|
||||
}
|
||||
}
|
||||
override val fullName get() = ""
|
||||
override val shortDescr get() = null
|
||||
override val image get() = null
|
||||
|
||||
val initiated get() = (pccConnStatus.initiated ?: false) && !viaContactUri
|
||||
|
||||
+1
-1
@@ -573,7 +573,7 @@ object ChatController {
|
||||
|
||||
suspend fun startChatWithTemporaryDatabase(ctrl: ChatCtrl, netCfg: NetCfg): User? {
|
||||
Log.d(TAG, "startChatWithTemporaryDatabase")
|
||||
val migrationActiveUser = apiGetActiveUser(null, ctrl) ?: apiCreateActiveUser(null, Profile(displayName = "Temp", fullName = ""), ctrl = ctrl)
|
||||
val migrationActiveUser = apiGetActiveUser(null, ctrl) ?: apiCreateActiveUser(null, Profile(displayName = "Temp", fullName = "", shortDescr = null), ctrl = ctrl)
|
||||
if (!apiSetNetworkConfig(netCfg, ctrl = ctrl)) {
|
||||
Log.e(TAG, "Error setting network config, stopping migration")
|
||||
return null
|
||||
|
||||
+14
-5
@@ -46,6 +46,7 @@ fun CreateProfile(chatModel: ChatModel, close: () -> Unit) {
|
||||
.padding(top = 20.dp)
|
||||
) {
|
||||
val displayName = rememberSaveable { mutableStateOf("") }
|
||||
val shortDescr = rememberSaveable { mutableStateOf("") }
|
||||
val focusRequester = remember { FocusRequester() }
|
||||
|
||||
ColumnWithScrollBar {
|
||||
@@ -66,6 +67,14 @@ fun CreateProfile(chatModel: ChatModel, close: () -> Unit) {
|
||||
}
|
||||
}
|
||||
ProfileNameField(displayName, "", { it.trim() == mkValidName(it) }, focusRequester)
|
||||
|
||||
// TODO enable in v6.4.1, limit to 160 characters
|
||||
|
||||
// Text(
|
||||
// stringResource(MR.strings.short_descr),
|
||||
// fontSize = 16.sp
|
||||
// )
|
||||
// ProfileNameField(shortDescr, "")
|
||||
}
|
||||
SettingsActionItem(
|
||||
painterResource(MR.images.ic_check),
|
||||
@@ -75,7 +84,7 @@ fun CreateProfile(chatModel: ChatModel, close: () -> Unit) {
|
||||
iconColor = MaterialTheme.colors.primary,
|
||||
click = {
|
||||
if (chatModel.localUserCreated.value == true) {
|
||||
createProfileInProfiles(chatModel, displayName.value, close)
|
||||
createProfileInProfiles(chatModel, displayName.value, shortDescr.value, close)
|
||||
} else {
|
||||
createProfileInNoProfileSetup(displayName.value, close)
|
||||
}
|
||||
@@ -162,7 +171,7 @@ fun CreateFirstProfile(chatModel: ChatModel, close: () -> Unit) {
|
||||
|
||||
fun createProfileInNoProfileSetup(displayName: String, close: () -> Unit) {
|
||||
withBGApi {
|
||||
val user = controller.apiCreateActiveUser(null, Profile(displayName.trim(), "", null)) ?: return@withBGApi
|
||||
val user = controller.apiCreateActiveUser(null, Profile(displayName.trim(), "", null, null)) ?: return@withBGApi
|
||||
if (!chatModel.connectedToRemote()) {
|
||||
chatModel.localUserCreated.value = true
|
||||
}
|
||||
@@ -173,11 +182,11 @@ fun createProfileInNoProfileSetup(displayName: String, close: () -> Unit) {
|
||||
}
|
||||
}
|
||||
|
||||
fun createProfileInProfiles(chatModel: ChatModel, displayName: String, close: () -> Unit) {
|
||||
fun createProfileInProfiles(chatModel: ChatModel, displayName: String, shortDescr: String, close: () -> Unit) {
|
||||
withBGApi {
|
||||
val rhId = chatModel.remoteHostId()
|
||||
val user = chatModel.controller.apiCreateActiveUser(
|
||||
rhId, Profile(displayName.trim(), "", null)
|
||||
rhId, Profile(displayName.trim(), "", shortDescr.trim().ifEmpty { null }, null)
|
||||
) ?: return@withBGApi
|
||||
chatModel.currentUser.value = user
|
||||
if (chatModel.users.isEmpty()) {
|
||||
@@ -196,7 +205,7 @@ fun createProfileInProfiles(chatModel: ChatModel, displayName: String, close: ()
|
||||
fun createProfileOnboarding(chatModel: ChatModel, displayName: String, close: () -> Unit) {
|
||||
withBGApi {
|
||||
chatModel.currentUser.value = chatModel.controller.apiCreateActiveUser(
|
||||
null, Profile(displayName.trim(), "", null)
|
||||
null, Profile(displayName.trim(), "", null, null)
|
||||
) ?: return@withBGApi
|
||||
chatModel.localUserCreated.value = true
|
||||
val onboardingStage = chatModel.controller.appPrefs.onboardingStage
|
||||
|
||||
+38
-15
@@ -706,15 +706,16 @@ fun ChatInfoLayout(
|
||||
@Composable
|
||||
fun ChatInfoHeader(cInfo: ChatInfo, contact: Contact) {
|
||||
Column(
|
||||
Modifier.padding(horizontal = 8.dp),
|
||||
Modifier.padding(horizontal = DEFAULT_PADDING),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
ChatInfoImage(cInfo, size = 192.dp, iconColor = if (isInDarkTheme()) GroupDark else SettingsSecondaryLight)
|
||||
val displayName = contact.profile.displayName.trim()
|
||||
val text = buildAnnotatedString {
|
||||
if (contact.verified) {
|
||||
appendInlineContent(id = "shieldIcon")
|
||||
}
|
||||
append(contact.profile.displayName)
|
||||
append(displayName)
|
||||
}
|
||||
val inlineContent: Map<String, InlineTextContent> = mapOf(
|
||||
"shieldIcon" to InlineTextContent(
|
||||
@@ -724,10 +725,11 @@ fun ChatInfoHeader(cInfo: ChatInfo, contact: Contact) {
|
||||
}
|
||||
)
|
||||
val clipboard = LocalClipboardManager.current
|
||||
val copyNameToClipboard = {
|
||||
clipboard.setText(AnnotatedString(contact.profile.displayName))
|
||||
val copyNameToClipboard = fun (name: String) {
|
||||
clipboard.setText(AnnotatedString(name))
|
||||
showToast(generalGetString(MR.strings.copied))
|
||||
}
|
||||
val copyDisplayName = { copyNameToClipboard(displayName) }
|
||||
Text(
|
||||
text,
|
||||
inlineContent = inlineContent,
|
||||
@@ -735,18 +737,39 @@ fun ChatInfoHeader(cInfo: ChatInfo, contact: Contact) {
|
||||
textAlign = TextAlign.Center,
|
||||
maxLines = 3,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
modifier = Modifier.combinedClickable(onClick = copyNameToClipboard, onLongClick = copyNameToClipboard).onRightClick(copyNameToClipboard)
|
||||
modifier = Modifier.combinedClickable(onClick = copyDisplayName, onLongClick = copyDisplayName).onRightClick(copyDisplayName)
|
||||
)
|
||||
ChatInfoDescription(cInfo, displayName, copyNameToClipboard)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ChatInfoDescription(c: NamedChat, displayName: String, copyNameToClipboard: (String) -> Unit) {
|
||||
val fullName = c.fullName.trim()
|
||||
if (fullName != "" && fullName != displayName && fullName != c.displayName.trim()) {
|
||||
val copyFullName = { copyNameToClipboard(fullName) }
|
||||
Text(
|
||||
fullName, style = MaterialTheme.typography.h2,
|
||||
color = MaterialTheme.colors.onBackground,
|
||||
textAlign = TextAlign.Center,
|
||||
maxLines = 3,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
modifier = Modifier.padding(top = DEFAULT_PADDING_HALF).combinedClickable(onClick = copyFullName, onLongClick = copyFullName).onRightClick(copyFullName)
|
||||
)
|
||||
}
|
||||
val descr = c.shortDescr?.trim()
|
||||
if (descr != null && descr != "") {
|
||||
val copyDescr = { copyNameToClipboard(descr) }
|
||||
Text(
|
||||
descr,
|
||||
style = MaterialTheme.typography.body2,
|
||||
color = MaterialTheme.colors.onBackground,
|
||||
textAlign = TextAlign.Center,
|
||||
maxLines = 4,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
lineHeight = 21.sp,
|
||||
modifier = Modifier.padding(top = DEFAULT_PADDING_HALF).combinedClickable(onClick = copyDescr, onLongClick = copyDescr).onRightClick(copyDescr)
|
||||
)
|
||||
if (cInfo.fullName != "" && cInfo.fullName != cInfo.displayName && cInfo.fullName != contact.profile.displayName) {
|
||||
Text(
|
||||
cInfo.fullName, style = MaterialTheme.typography.h2,
|
||||
color = MaterialTheme.colors.onBackground,
|
||||
textAlign = TextAlign.Center,
|
||||
maxLines = 4,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
modifier = Modifier.combinedClickable(onClick = copyNameToClipboard, onLongClick = copyNameToClipboard).onRightClick(copyNameToClipboard)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+10
-16
@@ -724,33 +724,27 @@ fun ChatTTLOption(chatItemTTL: State<ChatItemTTL?>, setChatItemTTL: (ChatItemTTL
|
||||
@Composable
|
||||
private fun GroupChatInfoHeader(cInfo: ChatInfo, groupInfo: GroupInfo) {
|
||||
Column(
|
||||
Modifier.padding(horizontal = 8.dp),
|
||||
Modifier.padding(horizontal = DEFAULT_PADDING),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
ChatInfoImage(cInfo, size = 192.dp, iconColor = if (isInDarkTheme()) GroupDark else SettingsSecondaryLight)
|
||||
val clipboard = LocalClipboardManager.current
|
||||
val copyNameToClipboard = {
|
||||
clipboard.setText(AnnotatedString(groupInfo.groupProfile.displayName))
|
||||
val copyNameToClipboard = fun(name: String) {
|
||||
clipboard.setText(AnnotatedString(name))
|
||||
showToast(generalGetString(MR.strings.copied))
|
||||
}
|
||||
val displayName = groupInfo.groupProfile.displayName.trim()
|
||||
val copyDisplayName = { copyNameToClipboard(displayName) }
|
||||
Text(
|
||||
groupInfo.groupProfile.displayName, style = MaterialTheme.typography.h1.copy(fontWeight = FontWeight.Normal),
|
||||
displayName,
|
||||
style = MaterialTheme.typography.h1.copy(fontWeight = FontWeight.Normal),
|
||||
color = MaterialTheme.colors.onBackground,
|
||||
textAlign = TextAlign.Center,
|
||||
maxLines = 4,
|
||||
maxLines = 3,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
modifier = Modifier.combinedClickable(onClick = copyNameToClipboard, onLongClick = copyNameToClipboard).onRightClick(copyNameToClipboard)
|
||||
modifier = Modifier.combinedClickable(onClick = copyDisplayName, onLongClick = copyDisplayName).onRightClick(copyDisplayName)
|
||||
)
|
||||
if (cInfo.fullName != "" && cInfo.fullName != cInfo.displayName && cInfo.fullName != groupInfo.groupProfile.displayName) {
|
||||
Text(
|
||||
cInfo.fullName, style = MaterialTheme.typography.h2,
|
||||
color = MaterialTheme.colors.onBackground,
|
||||
textAlign = TextAlign.Center,
|
||||
maxLines = 8,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
modifier = Modifier.combinedClickable(onClick = copyNameToClipboard, onLongClick = copyNameToClipboard).onRightClick(copyNameToClipboard)
|
||||
)
|
||||
}
|
||||
ChatInfoDescription(cInfo, displayName, copyNameToClipboard)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+8
-14
@@ -568,11 +568,12 @@ fun GroupMemberInfoHeader(member: GroupMember) {
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
MemberProfileImage(size = 192.dp, member, color = if (isInDarkTheme()) GroupDark else SettingsSecondaryLight)
|
||||
val displayName = member.displayName.trim() // alias if set
|
||||
val text = buildAnnotatedString {
|
||||
if (member.verified) {
|
||||
appendInlineContent(id = "shieldIcon")
|
||||
}
|
||||
append(member.displayName)
|
||||
append(displayName)
|
||||
}
|
||||
val inlineContent: Map<String, InlineTextContent> = mapOf(
|
||||
"shieldIcon" to InlineTextContent(
|
||||
@@ -582,10 +583,11 @@ fun GroupMemberInfoHeader(member: GroupMember) {
|
||||
}
|
||||
)
|
||||
val clipboard = LocalClipboardManager.current
|
||||
val copyNameToClipboard = {
|
||||
clipboard.setText(AnnotatedString(member.displayName))
|
||||
val copyNameToClipboard = fun(name: String) {
|
||||
clipboard.setText(AnnotatedString(name))
|
||||
showToast(generalGetString(MR.strings.copied))
|
||||
}
|
||||
val copyDisplayName = { copyNameToClipboard(displayName) }
|
||||
Text(
|
||||
text,
|
||||
inlineContent = inlineContent,
|
||||
@@ -593,18 +595,10 @@ fun GroupMemberInfoHeader(member: GroupMember) {
|
||||
textAlign = TextAlign.Center,
|
||||
maxLines = 3,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
modifier = Modifier.combinedClickable(onClick = copyNameToClipboard, onLongClick = copyNameToClipboard).onRightClick(copyNameToClipboard)
|
||||
modifier = Modifier.combinedClickable(onClick = copyDisplayName, onLongClick = copyDisplayName).onRightClick(copyDisplayName)
|
||||
)
|
||||
if (member.fullName != "" && member.fullName != member.displayName) {
|
||||
Text(
|
||||
member.fullName, style = MaterialTheme.typography.h2,
|
||||
color = MaterialTheme.colors.onBackground,
|
||||
textAlign = TextAlign.Center,
|
||||
maxLines = 4,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
modifier = Modifier.combinedClickable(onClick = copyNameToClipboard, onLongClick = copyNameToClipboard).onRightClick(copyNameToClipboard)
|
||||
)
|
||||
}
|
||||
// passing actual display name here, as alias is used above
|
||||
ChatInfoDescription(member, member.memberProfile.displayName.trim(), copyNameToClipboard)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+20
-5
@@ -56,14 +56,16 @@ fun GroupProfileLayout(
|
||||
val bottomSheetModalState = rememberModalBottomSheetState(initialValue = ModalBottomSheetValue.Hidden)
|
||||
val displayName = rememberSaveable { mutableStateOf(groupProfile.displayName) }
|
||||
val fullName = rememberSaveable { mutableStateOf(groupProfile.fullName) }
|
||||
val shortDescr = rememberSaveable { mutableStateOf(groupProfile.shortDescr ?: "") }
|
||||
val chosenImage = rememberSaveable { mutableStateOf<URI?>(null) }
|
||||
val profileImage = rememberSaveable { mutableStateOf(groupProfile.image) }
|
||||
val scope = rememberCoroutineScope()
|
||||
val scrollState = rememberScrollState()
|
||||
val focusRequester = remember { FocusRequester() }
|
||||
val dataUnchanged =
|
||||
displayName.value == groupProfile.displayName &&
|
||||
fullName.value == groupProfile.fullName &&
|
||||
displayName.value.trim() == groupProfile.displayName &&
|
||||
fullName.value.trim() == groupProfile.fullName &&
|
||||
shortDescr.value.trim() == (groupProfile.shortDescr ?: "") &&
|
||||
groupProfile.image == profileImage.value
|
||||
val closeWithAlert = {
|
||||
if (dataUnchanged || !canUpdateProfile(displayName.value, groupProfile)) {
|
||||
@@ -73,7 +75,8 @@ fun GroupProfileLayout(
|
||||
saveProfile(
|
||||
groupProfile.copy(
|
||||
displayName = displayName.value.trim(),
|
||||
fullName = fullName.value,
|
||||
fullName = fullName.value.trim(),
|
||||
shortDescr = shortDescr.value.trim().ifEmpty { null },
|
||||
image = profileImage.value
|
||||
)
|
||||
)
|
||||
@@ -130,7 +133,7 @@ fun GroupProfileLayout(
|
||||
}
|
||||
}
|
||||
ProfileNameField(displayName, "", { isValidNewProfileName(it, groupProfile) }, focusRequester)
|
||||
if (groupProfile.fullName.isNotEmpty() && groupProfile.fullName != groupProfile.displayName) {
|
||||
if (groupProfile.fullName.trim().isNotEmpty() && groupProfile.fullName.trim() != groupProfile.displayName.trim()) {
|
||||
Spacer(Modifier.height(DEFAULT_PADDING))
|
||||
Text(
|
||||
stringResource(MR.strings.group_full_name_field),
|
||||
@@ -139,6 +142,17 @@ fun GroupProfileLayout(
|
||||
)
|
||||
ProfileNameField(fullName)
|
||||
}
|
||||
|
||||
// TODO enable in v6.4.1, limit to 160 characters
|
||||
|
||||
// Spacer(Modifier.height(DEFAULT_PADDING))
|
||||
// Text(
|
||||
// stringResource(MR.strings.group_short_descr_field),
|
||||
// fontSize = 16.sp,
|
||||
// modifier = Modifier.padding(bottom = DEFAULT_PADDING_HALF)
|
||||
// )
|
||||
// ProfileNameField(shortDescr)
|
||||
|
||||
Spacer(Modifier.height(DEFAULT_PADDING))
|
||||
val enabled = !dataUnchanged && canUpdateProfile(displayName.value, groupProfile)
|
||||
if (enabled) {
|
||||
@@ -148,7 +162,8 @@ fun GroupProfileLayout(
|
||||
saveProfile(
|
||||
groupProfile.copy(
|
||||
displayName = displayName.value.trim(),
|
||||
fullName = fullName.value,
|
||||
fullName = fullName.value.trim(),
|
||||
shortDescr = shortDescr.value.trim().ifEmpty { null },
|
||||
image = profileImage.value
|
||||
)
|
||||
)
|
||||
|
||||
+1
-1
@@ -194,7 +194,7 @@ fun CIGroupInvitationViewLongNamePreview() {
|
||||
CIGroupInvitationView(
|
||||
ci = ChatItem.getGroupInvitationSample(),
|
||||
groupInvitation = CIGroupInvitation.getSample(
|
||||
groupProfile = GroupProfile("group_with_a_really_really_really_long_name", "Group With A Really Really Really Long Name"),
|
||||
groupProfile = GroupProfile("group_with_a_really_really_really_long_name", "Group With A Really Really Really Long Name", shortDescr = null),
|
||||
status = CIGroupInvitationStatus.Accepted
|
||||
),
|
||||
memberRole = GroupMemberRole.Admin,
|
||||
|
||||
+1
-1
@@ -82,7 +82,7 @@ private fun deleteStorageAndRestart(m: ChatModel, password: String, completed: (
|
||||
}
|
||||
var profile: Profile? = null
|
||||
if (!displayName.isNullOrEmpty()) {
|
||||
profile = Profile(displayName = displayName, fullName = "")
|
||||
profile = Profile(displayName = displayName, fullName = "", shortDescr = null)
|
||||
}
|
||||
val createdUser = m.controller.apiCreateActiveUser(null, profile, pastTimestamp = true)
|
||||
m.currentUser.value = createdUser
|
||||
|
||||
+1
@@ -140,6 +140,7 @@ fun AddGroupLayout(
|
||||
createGroup(incognito.value, GroupProfile(
|
||||
displayName = displayName.value.trim(),
|
||||
fullName = "",
|
||||
shortDescr = null,
|
||||
image = profileImage.value,
|
||||
groupPreferences = GroupPreferences(history = GroupPreference(GroupFeatureEnabled.ON))
|
||||
))
|
||||
|
||||
+24
-10
@@ -40,9 +40,10 @@ fun UserProfileView(chatModel: ChatModel, close: () -> Unit) {
|
||||
UserProfileLayout(
|
||||
profile = profile,
|
||||
close,
|
||||
saveProfile = { displayName, fullName, image ->
|
||||
saveProfile = { displayName, fullName, shortDescr, image ->
|
||||
withBGApi {
|
||||
val updated = chatModel.controller.apiUpdateProfile(user.remoteHostId, profile.copy(displayName = displayName.trim(), fullName = fullName, image = image))
|
||||
val updatedProfile = profile.copy(displayName = displayName.trim(), fullName = fullName.trim(), shortDescr = shortDescr.trim().ifEmpty { null }, image = image)
|
||||
val updated = chatModel.controller.apiUpdateProfile(user.remoteHostId, updatedProfile)
|
||||
if (updated != null) {
|
||||
val (newProfile, _) = updated
|
||||
chatModel.updateCurrentUser(user.remoteHostId, newProfile)
|
||||
@@ -59,11 +60,12 @@ fun UserProfileView(chatModel: ChatModel, close: () -> Unit) {
|
||||
fun UserProfileLayout(
|
||||
profile: Profile,
|
||||
close: () -> Unit,
|
||||
saveProfile: (String, String, String?) -> Unit,
|
||||
saveProfile: (String, String, String, String?) -> Unit,
|
||||
) {
|
||||
val bottomSheetModalState = rememberModalBottomSheetState(initialValue = ModalBottomSheetValue.Hidden)
|
||||
val displayName = remember { mutableStateOf(profile.displayName) }
|
||||
val fullName = remember { mutableStateOf(profile.fullName) }
|
||||
val shortDescr = remember { mutableStateOf(profile.shortDescr ?: "") }
|
||||
val chosenImage = rememberSaveable { mutableStateOf<URI?>(null) }
|
||||
val profileImage = rememberSaveable { mutableStateOf(profile.image) }
|
||||
val scope = rememberCoroutineScope()
|
||||
@@ -85,14 +87,15 @@ fun UserProfileLayout(
|
||||
sheetShape = RoundedCornerShape(topStart = 18.dp, topEnd = 18.dp)
|
||||
) {
|
||||
val dataUnchanged =
|
||||
displayName.value == profile.displayName &&
|
||||
fullName.value == profile.fullName &&
|
||||
displayName.value.trim() == profile.displayName &&
|
||||
fullName.value.trim() == profile.fullName &&
|
||||
shortDescr.value.trim() == (profile.shortDescr ?: "") &&
|
||||
profile.image == profileImage.value
|
||||
val closeWithAlert = {
|
||||
if (dataUnchanged || !canSaveProfile(displayName.value, profile)) {
|
||||
close()
|
||||
} else {
|
||||
showUnsavedChangesAlert({ saveProfile(displayName.value, fullName.value, profileImage.value) }, close)
|
||||
showUnsavedChangesAlert({ saveProfile(displayName.value, fullName.value, shortDescr.value, profileImage.value) }, close)
|
||||
}
|
||||
}
|
||||
ModalView(close = closeWithAlert) {
|
||||
@@ -144,9 +147,20 @@ fun UserProfileLayout(
|
||||
)
|
||||
ProfileNameField(fullName)
|
||||
}
|
||||
|
||||
// TODO enable in v6.4.1, limit to 160 characters
|
||||
|
||||
// Spacer(Modifier.height(DEFAULT_PADDING))
|
||||
// Text(
|
||||
// stringResource(MR.strings.short_descr__field),
|
||||
// fontSize = 16.sp,
|
||||
// modifier = Modifier.padding(bottom = DEFAULT_PADDING_HALF)
|
||||
// )
|
||||
// ProfileNameField(shortDescr)
|
||||
|
||||
Spacer(Modifier.height(DEFAULT_PADDING))
|
||||
val enabled = !dataUnchanged && canSaveProfile(displayName.value, profile)
|
||||
val saveModifier: Modifier = Modifier.clickable(enabled) { saveProfile(displayName.value, fullName.value, profileImage.value) }
|
||||
val saveModifier: Modifier = Modifier.clickable(enabled) { saveProfile(displayName.value, fullName.value, shortDescr.value, profileImage.value) }
|
||||
val saveColor: Color = if (enabled) MaterialTheme.colors.primary else MaterialTheme.colors.secondary
|
||||
Text(
|
||||
stringResource(MR.strings.save_and_notify_contacts),
|
||||
@@ -209,7 +223,7 @@ private fun isValidNewProfileName(displayName: String, profile: Profile): Boolea
|
||||
displayName == profile.displayName || isValidDisplayName(displayName.trim())
|
||||
|
||||
private fun showFullName(profile: Profile): Boolean =
|
||||
profile.fullName.isNotEmpty() && profile.fullName != profile.displayName
|
||||
profile.fullName.trim().isNotEmpty() && profile.fullName.trim() != profile.displayName.trim()
|
||||
|
||||
private fun canSaveProfile(displayName: String, profile: Profile): Boolean =
|
||||
displayName.trim().isNotEmpty() && isValidNewProfileName(displayName, profile)
|
||||
@@ -225,7 +239,7 @@ fun PreviewUserProfileLayoutEditOff() {
|
||||
UserProfileLayout(
|
||||
profile = Profile.sampleData,
|
||||
close = {},
|
||||
saveProfile = { _, _, _ -> }
|
||||
saveProfile = { _, _, _, _ -> }
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -241,7 +255,7 @@ fun PreviewUserProfileLayoutEditOn() {
|
||||
UserProfileLayout(
|
||||
profile = Profile.sampleData,
|
||||
close = {},
|
||||
saveProfile = { _, _, _ -> }
|
||||
saveProfile = { _, _, _, _ -> }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1108,6 +1108,7 @@
|
||||
<!-- User profile details - UserProfileView.kt -->
|
||||
<string name="display_name__field">Profile name:</string>
|
||||
<string name="full_name__field">Full name:</string>
|
||||
<string name="short_descr__field">Bio:</string>
|
||||
<string name="your_current_profile">Your current profile</string>
|
||||
<string name="your_profile_is_stored_on_device_and_shared_only_with_contacts_simplex_cannot_see_it">Your profile is stored on your device and shared only with your contacts. SimpleX servers cannot see your profile.</string>
|
||||
<string name="edit_image">Edit image</string>
|
||||
@@ -1137,6 +1138,7 @@
|
||||
<string name="profile_is_only_shared_with_your_contacts">The profile is only shared with your contacts.</string>
|
||||
<string name="display_name_cannot_contain_whitespace">Display name cannot contain whitespace.</string>
|
||||
<string name="display_name">Enter your name:</string>
|
||||
<string name="short_descr">Your bio:</string>
|
||||
<string name="create_profile_button">Create</string>
|
||||
<string name="create_another_profile_button">Create profile</string>
|
||||
<string name="create_address_button">Create</string>
|
||||
@@ -1914,6 +1916,7 @@
|
||||
<string name="group_is_decentralized">Fully decentralized – visible only to members.</string>
|
||||
<string name="group_display_name_field">Enter group name:</string>
|
||||
<string name="group_full_name_field">Group full name:</string>
|
||||
<string name="group_short_descr_field">Short description:</string>
|
||||
<string name="group_main_profile_sent">Your chat profile will be sent to group members</string>
|
||||
<string name="chat_main_profile_sent">Your chat profile will be sent to chat members</string>
|
||||
<string name="create_group_button">Create group</string>
|
||||
|
||||
@@ -234,14 +234,19 @@ directoryServiceEvent st opts@DirectoryOpts {adminUsers, superUsers, serviceName
|
||||
getGroupReg st groupId >>= \case
|
||||
Just gr -> action gr
|
||||
Nothing -> logError $ "Error: " <> err <> ", group: " <> localDisplayName <> ", can't find group registration ID " <> tshow groupId
|
||||
groupInfoText GroupProfile {displayName = n, fullName = fn, description = d} =
|
||||
n <> (if n == fn || T.null fn then "" else " (" <> fn <> ")") <> maybe "" ("\nWelcome message:\n" <>) d
|
||||
groupInfoText p@GroupProfile {description = d} = groupNameDescr p <> maybe "" ("\nWelcome message:\n" <>) d
|
||||
groupNameDescr GroupProfile {displayName = n, fullName = fn, shortDescr = sd_} =
|
||||
n <> maybe "" (\d' -> " (" <> d' <> ")") descr
|
||||
where
|
||||
descr
|
||||
| n == fn || T.null fn = if sd_ == Just "" then Nothing else sd_
|
||||
| otherwise = Just fn
|
||||
userGroupReference gr GroupInfo {groupProfile = GroupProfile {displayName}} = userGroupReference' gr displayName
|
||||
userGroupReference' GroupReg {userGroupRegId} displayName = groupReference' userGroupRegId displayName
|
||||
groupReference GroupInfo {groupId, groupProfile = GroupProfile {displayName}} = groupReference' groupId displayName
|
||||
groupReference' groupId displayName = "ID " <> tshow groupId <> " (" <> displayName <> ")"
|
||||
groupAlreadyListed GroupInfo {groupProfile = GroupProfile {displayName, fullName}} =
|
||||
"The group " <> displayName <> " (" <> fullName <> ") is already listed in the directory, please choose another name."
|
||||
groupAlreadyListed GroupInfo {groupProfile = p} =
|
||||
"The group " <> groupNameDescr p <> " is already listed in the directory, please choose another name."
|
||||
|
||||
getGroups :: Text -> IO (Maybe [(GroupInfo, GroupSummary)])
|
||||
getGroups = getGroups_ . Just
|
||||
@@ -295,7 +300,7 @@ directoryServiceEvent st opts@DirectoryOpts {adminUsers, superUsers, serviceName
|
||||
\Content and privacy policy: https://simplex.chat/docs/directory.html"
|
||||
|
||||
deGroupInvitation :: Contact -> GroupInfo -> GroupMemberRole -> GroupMemberRole -> IO ()
|
||||
deGroupInvitation ct g@GroupInfo {groupProfile = GroupProfile {displayName, fullName}} fromMemberRole memberRole = do
|
||||
deGroupInvitation ct g@GroupInfo {groupProfile = p@GroupProfile {displayName}} fromMemberRole memberRole = do
|
||||
logInfo $ "invited to group " <> viewGroupName g <> " by " <> viewContactName ct
|
||||
case badRolesMsg $ groupRolesStatus fromMemberRole memberRole of
|
||||
Just msg -> sendMessage cc ct msg
|
||||
@@ -308,7 +313,7 @@ directoryServiceEvent st opts@DirectoryOpts {adminUsers, superUsers, serviceName
|
||||
where
|
||||
askConfirmation = do
|
||||
ugrId <- addGroupReg st ct g GRSPendingConfirmation
|
||||
sendMessage cc ct $ "The group " <> displayName <> " (" <> fullName <> ") is already submitted to the directory.\nTo confirm the registration, please send:"
|
||||
sendMessage cc ct $ "The group " <> groupNameDescr p <> " is already submitted to the directory.\nTo confirm the registration, please send:"
|
||||
sendMessage cc ct $ "/confirm " <> tshow ugrId <> ":" <> viewName displayName
|
||||
|
||||
badRolesMsg :: GroupRolesStatus -> Maybe Text
|
||||
@@ -400,9 +405,9 @@ directoryServiceEvent st opts@DirectoryOpts {adminUsers, superUsers, serviceName
|
||||
GroupInfo {groupId, groupProfile = p} = fromGroup
|
||||
GroupInfo {groupProfile = p'} = toGroup
|
||||
sameProfile
|
||||
GroupProfile {displayName = n, fullName = fn, image = i, description = d}
|
||||
GroupProfile {displayName = n', fullName = fn', image = i', description = d'} =
|
||||
n == n' && fn == fn' && i == i' && d == d'
|
||||
GroupProfile {displayName = n, fullName = fn, shortDescr = sd, image = i, description = d}
|
||||
GroupProfile {displayName = n', fullName = fn', shortDescr = sd', image = i', description = d'} =
|
||||
n == n' && fn == fn' && i == i' && sd == sd' && d == d'
|
||||
groupLinkAdded gr byMember = do
|
||||
getDuplicateGroup toGroup >>= \case
|
||||
Nothing -> notifyOwner gr "Error: getDuplicateGroup. Please notify the developers."
|
||||
|
||||
@@ -110,6 +110,7 @@ library
|
||||
Simplex.Chat.Store.Postgres.Migrations.M20250526_short_links
|
||||
Simplex.Chat.Store.Postgres.Migrations.M20250702_contact_requests_remove_cascade_delete
|
||||
Simplex.Chat.Store.Postgres.Migrations.M20250704_groups_conn_link_prepared_connection
|
||||
Simplex.Chat.Store.Postgres.Migrations.M20250709_profile_short_descr
|
||||
else
|
||||
exposed-modules:
|
||||
Simplex.Chat.Archive
|
||||
@@ -245,6 +246,7 @@ library
|
||||
Simplex.Chat.Store.SQLite.Migrations.M20250526_short_links
|
||||
Simplex.Chat.Store.SQLite.Migrations.M20250702_contact_requests_remove_cascade_delete
|
||||
Simplex.Chat.Store.SQLite.Migrations.M20250704_groups_conn_link_prepared_connection
|
||||
Simplex.Chat.Store.SQLite.Migrations.M20250709_profile_short_descr
|
||||
other-modules:
|
||||
Paths_simplex_chat
|
||||
hs-source-dirs:
|
||||
|
||||
@@ -531,7 +531,7 @@ data ChatCommand
|
||||
| CancelFile FileTransferId
|
||||
| FileStatus FileTransferId
|
||||
| ShowProfile -- UserId (not used in UI)
|
||||
| UpdateProfile ContactName Text -- UserId (not used in UI)
|
||||
| UpdateProfile ContactName (Maybe Text) -- UserId (not used in UI)
|
||||
| UpdateProfileImage (Maybe ImageData) -- UserId (not used in UI)
|
||||
| ShowProfileImage
|
||||
| SetUserFeature AChatFeature FeatureAllowed -- UserId (not used in UI)
|
||||
|
||||
@@ -107,7 +107,7 @@ createActiveUser cc = do
|
||||
where
|
||||
loop = do
|
||||
displayName <- T.pack <$> getWithPrompt "display name"
|
||||
let profile = Just Profile {displayName, fullName = "", image = Nothing, contactLink = Nothing, preferences = Nothing}
|
||||
let profile = Just Profile {displayName, fullName = "", shortDescr = Nothing, image = Nothing, contactLink = Nothing, preferences = Nothing}
|
||||
execChatCommand' (CreateActiveUser NewUser {profile, pastTimestamp = False}) 0 `runReaderT` cc >>= \case
|
||||
Right (CRActiveUser user) -> pure user
|
||||
r -> printResponseEvent (Nothing, Nothing) (config cc) r >> loop
|
||||
|
||||
@@ -122,7 +122,7 @@ groupsHelpInfo =
|
||||
map
|
||||
styleMarkdown
|
||||
[ green "Group commands:",
|
||||
indent <> highlight "/group <group> [<full_name>] " <> " - create group",
|
||||
indent <> highlight "/group <group> [<description>] " <> " - create group",
|
||||
indent <> highlight "/add <group> <contact> [<role>] " <> " - add contact to group, roles: " <> highlight "owner" <> ", " <> highlight "admin" <> " (default), " <> highlight "member",
|
||||
indent <> highlight "/join <group> " <> " - accept group invitation",
|
||||
indent <> highlight "/members <group> " <> " - list group members",
|
||||
@@ -131,8 +131,10 @@ groupsHelpInfo =
|
||||
indent <> highlight "/clear #<group> " <> " - clear all messages in the group locally",
|
||||
indent <> highlight "/delete #<group> " <> " - delete group and all messages",
|
||||
indent <> highlight "/gp <group> " <> " - view group profile",
|
||||
indent <> highlight "/gp <group> <name> [<full_name>] " <> " - update group profile names",
|
||||
indent <> highlight "/group_descr <group> [<descr>] " <> " - update/remove group description",
|
||||
indent <> highlight "/gp <group> <name> [<description>] " <> " - update group profile names",
|
||||
indent <> highlight "/set welcome <group> <welcome> " <> " - set group welcome message",
|
||||
indent <> highlight "/delete welcome <group> " <> " - delete group welcome message",
|
||||
indent <> highlight "/show welcome <group> " <> " - show group welcome message",
|
||||
indent <> highlight "/groups " <> " - list groups",
|
||||
indent <> highlight "#<group> <message> " <> " - send message to group",
|
||||
"",
|
||||
|
||||
@@ -2507,8 +2507,8 @@ processChatCommand vr nm = \case
|
||||
APIUpdateGroupProfile groupId p' -> withUser $ \user -> do
|
||||
g <- withFastStore $ \db -> getGroup db vr user groupId
|
||||
runUpdateGroupProfile user g p'
|
||||
UpdateGroupNames gName GroupProfile {displayName, fullName} ->
|
||||
updateGroupProfileByName gName $ \p -> p {displayName, fullName}
|
||||
UpdateGroupNames gName p'@GroupProfile {displayName, fullName, shortDescr} ->
|
||||
updateGroupProfileByName gName $ \p -> p {displayName, fullName, shortDescr}
|
||||
ShowGroupProfile gName -> withUser $ \user ->
|
||||
CRGroupProfile user <$> withFastStore (\db -> getGroupInfoByName db vr user gName)
|
||||
UpdateGroupDescription gName description ->
|
||||
@@ -2729,8 +2729,8 @@ processChatCommand vr nm = \case
|
||||
fileStatus <- withFastStore $ \db -> getFileTransferProgress db user fileId
|
||||
pure $ CRFileTransferStatus user fileStatus
|
||||
ShowProfile -> withUser $ \user@User {profile} -> pure $ CRUserProfile user (fromLocalProfile profile)
|
||||
UpdateProfile displayName fullName -> withUser $ \user@User {profile} -> do
|
||||
let p = (fromLocalProfile profile :: Profile) {displayName = displayName, fullName = fullName}
|
||||
UpdateProfile displayName shortDescr -> withUser $ \user@User {profile} -> do
|
||||
let p = (fromLocalProfile profile :: Profile) {displayName, shortDescr, fullName = ""}
|
||||
updateProfile user p
|
||||
UpdateProfileImage image -> withUser $ \user@User {profile} -> do
|
||||
let p = (fromLocalProfile profile :: Profile) {image}
|
||||
@@ -3151,9 +3151,9 @@ processChatCommand vr nm = \case
|
||||
let (newMs, oldMs) = partition (\m -> maxVersion (memberChatVRange m) >= businessChatPrefsVersion) ms
|
||||
-- this is a fallback to send the members with the old version correct profile of the business when preferences change
|
||||
unless (null oldMs) $ do
|
||||
GroupMember {memberProfile = LocalProfile {displayName, fullName, image}} <-
|
||||
GroupMember {memberProfile = LocalProfile {displayName, fullName, shortDescr, image}} <-
|
||||
withStore $ \db -> getGroupMemberByMemberId db vr user g businessId
|
||||
let p'' = p' {displayName, fullName, image} :: GroupProfile
|
||||
let p'' = p' {displayName, fullName, shortDescr, image} :: GroupProfile
|
||||
recipients = filter memberCurrentOrPending oldMs
|
||||
void $ sendGroupMessage user g' Nothing recipients (XGrpInfo p'')
|
||||
let ps' = fromMaybe defaultBusinessGroupPrefs $ groupPreferences p'
|
||||
@@ -3162,6 +3162,7 @@ processChatCommand vr nm = \case
|
||||
Nothing -> do
|
||||
setGroupLinkData'
|
||||
let recipients = filter memberCurrentOrPending ms
|
||||
liftIO $ putStrLn $ "about to sendGroupMessage to " <> show (length recipients)
|
||||
sendGroupMessage user g' Nothing recipients (XGrpInfo p')
|
||||
where
|
||||
setGroupLinkData' :: CM ()
|
||||
@@ -3553,14 +3554,14 @@ processChatCommand vr nm = \case
|
||||
business = maybe False businessAddress settings
|
||||
contactData
|
||||
| large = ContactShortLinkData p msg business
|
||||
| otherwise = ContactShortLinkData p {fullName = "", image = Nothing, contactLink = Nothing} Nothing business
|
||||
| otherwise = ContactShortLinkData p {fullName = "", shortDescr = Nothing, image = Nothing, contactLink = Nothing} Nothing business
|
||||
pure $ encodeShortLinkData large contactData
|
||||
groupShortLinkData :: GroupProfile -> CM UserLinkData
|
||||
groupShortLinkData gp = do
|
||||
large <- chatReadVar useLargeLinkData
|
||||
let gp'
|
||||
| large = gp
|
||||
| otherwise = gp {fullName = "", description = Nothing, image = Nothing, memberAdmission = Nothing}
|
||||
| otherwise = gp {fullName = "", shortDescr = Nothing, description = Nothing, image = Nothing, memberAdmission = Nothing}
|
||||
pure $ encodeShortLinkData large $ GroupShortLinkData gp'
|
||||
encodeShortLinkData :: J.ToJSON a => Bool -> a -> UserLinkData
|
||||
encodeShortLinkData large d =
|
||||
@@ -4609,7 +4610,7 @@ chatCommandP =
|
||||
"/set profile image " *> (UpdateProfileImage . Just . ImageData <$> imageP),
|
||||
"/delete profile image" $> UpdateProfileImage Nothing,
|
||||
"/show profile image" $> ShowProfileImage,
|
||||
("/profile " <|> "/p ") *> (uncurry UpdateProfile <$> profileNames),
|
||||
("/profile " <|> "/p ") *> (uncurry UpdateProfile <$> profileNameDescr),
|
||||
("/profile" <|> "/p") $> ShowProfile,
|
||||
"/set voice #" *> (SetGroupFeatureRole (AGFR SGFVoice) <$> displayNameP <*> _strP <*> optional memberRole),
|
||||
"/set voice @" *> (SetContactFeature (ACF SCFVoice) <$> displayNameP <*> optional (A.space *> strP)),
|
||||
@@ -4721,24 +4722,26 @@ chatCommandP =
|
||||
clearOverrides <- (" clear_overrides=" *> onOffP) <|> pure False
|
||||
pure UserMsgReceiptSettings {enable, clearOverrides}
|
||||
onOffP = ("on" $> True) <|> ("off" $> False)
|
||||
profileNames = (,) <$> displayNameP <*> fullNameP
|
||||
profileNameDescr = (,) <$> displayNameP <*> shortDescrP
|
||||
newUserP = do
|
||||
(cName, fullName) <- profileNames
|
||||
let profile = Just Profile {displayName = cName, fullName, image = Nothing, contactLink = Nothing, preferences = Nothing}
|
||||
(cName, shortDescr) <- profileNameDescr
|
||||
let profile = Just Profile {displayName = cName, fullName = "", shortDescr, image = Nothing, contactLink = Nothing, preferences = Nothing}
|
||||
pure NewUser {profile, pastTimestamp = False}
|
||||
jsonP :: J.FromJSON a => Parser a
|
||||
jsonP = J.eitherDecodeStrict' <$?> A.takeByteString
|
||||
groupProfile = do
|
||||
(gName, fullName) <- profileNames
|
||||
(gName, shortDescr) <- profileNameDescr
|
||||
let groupPreferences =
|
||||
Just
|
||||
(emptyGroupPrefs :: GroupPreferences)
|
||||
{ directMessages = Just DirectMessagesGroupPreference {enable = FEOn, role = Nothing},
|
||||
history = Just HistoryGroupPreference {enable = FEOn}
|
||||
}
|
||||
pure GroupProfile {displayName = gName, fullName, description = Nothing, image = Nothing, groupPreferences, memberAdmission = Nothing}
|
||||
pure GroupProfile {displayName = gName, fullName = "", shortDescr, description = Nothing, image = Nothing, groupPreferences, memberAdmission = Nothing}
|
||||
memberCriteriaP = ("all" $> Just MCAll) <|> ("off" $> Nothing)
|
||||
fullNameP = A.space *> textP <|> pure ""
|
||||
shortDescrP = do
|
||||
descr <- A.takeWhile1 isSpace *> (T.dropWhileEnd isSpace <$> textP) <|> pure ""
|
||||
pure $ if T.null descr then Nothing else Just $ T.take 160 descr
|
||||
textP = safeDecodeUtf8 <$> A.takeByteString
|
||||
pwdP = jsonP <|> (UserPwd . safeDecodeUtf8 <$> A.takeTill (== ' '))
|
||||
verifyCodeP = safeDecodeUtf8 <$> A.takeWhile (\c -> isDigit c || c == ' ')
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -2232,9 +2232,9 @@ processAgentMessageConn vr user@User {userId} corrId agentConnId agentMessage =
|
||||
createInternalChatItem user (CDDirectRcv c') ciContent Nothing
|
||||
where
|
||||
visibleProfileUpdated =
|
||||
n' /= n || fn' /= fn || i' /= i || cl' /= cl
|
||||
Profile {displayName = n, fullName = fn, image = i, contactLink = cl} = p
|
||||
Profile {displayName = n', fullName = fn', image = i', contactLink = cl'} = p'
|
||||
n' /= n || fn' /= fn || sd /= sd' || i' /= i || cl' /= cl
|
||||
Profile {displayName = n, fullName = fn, shortDescr = sd, image = i, contactLink = cl} = p
|
||||
Profile {displayName = n', fullName = fn', shortDescr = sd', image = i', contactLink = cl'} = p'
|
||||
|
||||
xInfoMember :: GroupInfo -> GroupMember -> Profile -> UTCTime -> CM ()
|
||||
xInfoMember gInfo m p' brokerTs = void $ processMemberProfileUpdate gInfo m p' True (Just brokerTs)
|
||||
|
||||
@@ -318,7 +318,7 @@ e2eInfoPQText =
|
||||
|
||||
ciGroupInvitationToText :: CIGroupInvitation -> GroupMemberRole -> Text
|
||||
ciGroupInvitationToText CIGroupInvitation {groupProfile = GroupProfile {displayName, fullName}} role =
|
||||
"invitation to join group " <> displayName <> optionalFullName displayName fullName <> " as " <> (decodeLatin1 . strEncode $ role)
|
||||
"invitation to join group " <> displayName <> optionalFullName displayName fullName Nothing <> " as " <> (decodeLatin1 . strEncode $ role)
|
||||
|
||||
rcvDirectEventToText :: RcvDirectEvent -> Text
|
||||
rcvDirectEventToText = \case
|
||||
@@ -402,7 +402,7 @@ sndConnEventToText = \case
|
||||
maybe "" (\GroupMemberRef {profile = Profile {displayName}} -> " for " <> displayName) member_
|
||||
|
||||
profileToText :: Profile -> Text
|
||||
profileToText Profile {displayName, fullName} = displayName <> optionalFullName displayName fullName
|
||||
profileToText Profile {displayName, fullName} = displayName <> optionalFullName displayName fullName Nothing
|
||||
|
||||
msgIntegrityError :: MsgErrorType -> Text
|
||||
msgIntegrityError = \case
|
||||
|
||||
@@ -10,7 +10,7 @@ generateRandomProfile :: IO Profile
|
||||
generateRandomProfile = do
|
||||
adjective <- pick adjectives
|
||||
noun <- pickNoun adjective 2
|
||||
pure $ Profile {displayName = adjective <> noun, fullName = "", image = Nothing, contactLink = Nothing, preferences = Nothing}
|
||||
pure $ Profile {displayName = adjective <> noun, fullName = "", shortDescr = Nothing, image = Nothing, contactLink = Nothing, preferences = Nothing}
|
||||
where
|
||||
pick :: [a] -> IO a
|
||||
pick xs = (xs !!) <$> randomRIO (0, length xs - 1)
|
||||
|
||||
@@ -111,7 +111,7 @@ getConnectionEntity db vr user@User {userId, userContactId} agentConnId = do
|
||||
db
|
||||
[sql|
|
||||
SELECT
|
||||
c.contact_profile_id, c.local_display_name, c.via_group, p.display_name, p.full_name, p.image, p.contact_link, p.local_alias, c.contact_used, c.contact_status, c.enable_ntfs, c.send_rcpts, c.favorite,
|
||||
c.contact_profile_id, c.local_display_name, c.via_group, p.display_name, p.full_name, p.short_descr, p.image, p.contact_link, p.local_alias, c.contact_used, c.contact_status, c.enable_ntfs, c.send_rcpts, c.favorite,
|
||||
p.preferences, c.user_preferences, c.created_at, c.updated_at, c.chat_ts, c.conn_full_link_to_connect, c.conn_short_link_to_connect, c.welcome_shared_msg_id, c.request_shared_msg_id, c.contact_request_id,
|
||||
c.contact_group_member_id, c.contact_grp_inv_sent, c.ui_themes, c.chat_deleted, c.custom_data, c.chat_item_ttl
|
||||
FROM contacts c
|
||||
@@ -120,8 +120,8 @@ getConnectionEntity db vr user@User {userId, userContactId} agentConnId = do
|
||||
|]
|
||||
(userId, contactId)
|
||||
toContact' :: Int64 -> Connection -> [ChatTagId] -> ContactRow' -> Contact
|
||||
toContact' contactId conn chatTags ((profileId, localDisplayName, viaGroup, displayName, fullName, image, contactLink, localAlias, BI contactUsed, contactStatus) :. (enableNtfs_, sendRcpts, BI favorite, preferences, userPreferences, createdAt, updatedAt, chatTs) :. preparedContactRow :. (contactRequestId, contactGroupMemberId, BI contactGrpInvSent, uiThemes, BI chatDeleted, customData, chatItemTTL)) =
|
||||
let profile = LocalProfile {profileId, displayName, fullName, image, contactLink, preferences, localAlias}
|
||||
toContact' contactId conn chatTags ((profileId, localDisplayName, viaGroup, displayName, fullName, shortDescr, image, contactLink, localAlias, BI contactUsed, contactStatus) :. (enableNtfs_, sendRcpts, BI favorite, preferences, userPreferences, createdAt, updatedAt, chatTs) :. preparedContactRow :. (contactRequestId, contactGroupMemberId, BI contactGrpInvSent, uiThemes, BI chatDeleted, customData, chatItemTTL)) =
|
||||
let profile = LocalProfile {profileId, displayName, fullName, shortDescr, image, contactLink, preferences, localAlias}
|
||||
chatSettings = ChatSettings {enableNtfs = fromMaybe MFAll enableNtfs_, sendRcpts = unBI <$> sendRcpts, favorite}
|
||||
mergedPreferences = contactUserPreferences user userPreferences preferences $ connIncognito conn
|
||||
activeConn = Just conn
|
||||
@@ -137,7 +137,7 @@ getConnectionEntity db vr user@User {userId, userContactId} agentConnId = do
|
||||
[sql|
|
||||
SELECT
|
||||
-- GroupInfo
|
||||
g.group_id, g.local_display_name, gp.display_name, gp.full_name, g.local_alias, gp.description, gp.image,
|
||||
g.group_id, g.local_display_name, gp.display_name, gp.full_name, gp.short_descr, g.local_alias, gp.description, gp.image,
|
||||
g.enable_ntfs, g.send_rcpts, g.favorite, gp.preferences, gp.member_admission,
|
||||
g.created_at, g.updated_at, g.chat_ts, g.user_member_profile_sent_at,
|
||||
g.conn_full_link_to_connect, g.conn_short_link_to_connect, g.conn_link_prepared_connection, g.conn_link_started_connection, g.welcome_shared_msg_id, g.request_shared_msg_id,
|
||||
@@ -147,12 +147,12 @@ getConnectionEntity db vr user@User {userId, userContactId} agentConnId = do
|
||||
mu.group_member_id, mu.group_id, mu.member_id, mu.peer_chat_min_version, mu.peer_chat_max_version, mu.member_role, mu.member_category,
|
||||
mu.member_status, mu.show_messages, mu.member_restriction, mu.invited_by, mu.invited_by_group_member_id, mu.local_display_name, mu.contact_id, mu.contact_profile_id, pu.contact_profile_id,
|
||||
-- GroupInfo {membership = GroupMember {memberProfile}}
|
||||
pu.display_name, pu.full_name, pu.image, pu.contact_link, pu.local_alias, pu.preferences,
|
||||
pu.display_name, pu.full_name, pu.short_descr, pu.image, pu.contact_link, pu.local_alias, pu.preferences,
|
||||
mu.created_at, mu.updated_at,
|
||||
mu.support_chat_ts, mu.support_chat_items_unread, mu.support_chat_items_member_attention, mu.support_chat_items_mentions, mu.support_chat_last_msg_from_member_ts,
|
||||
-- from GroupMember
|
||||
m.group_member_id, m.group_id, m.member_id, m.peer_chat_min_version, m.peer_chat_max_version, m.member_role, m.member_category, m.member_status, m.show_messages, m.member_restriction,
|
||||
m.invited_by, m.invited_by_group_member_id, m.local_display_name, m.contact_id, m.contact_profile_id, p.contact_profile_id, p.display_name, p.full_name, p.image, p.contact_link, p.local_alias, p.preferences,
|
||||
m.invited_by, m.invited_by_group_member_id, m.local_display_name, m.contact_id, m.contact_profile_id, p.contact_profile_id, p.display_name, p.full_name, p.short_descr, p.image, p.contact_link, p.local_alias, p.preferences,
|
||||
m.created_at, m.updated_at,
|
||||
m.support_chat_ts, m.support_chat_items_unread, m.support_chat_items_member_attention, m.support_chat_items_mentions, m.support_chat_last_msg_from_member_ts
|
||||
FROM group_members m
|
||||
|
||||
@@ -72,7 +72,7 @@ createOrUpdateContactRequest
|
||||
isSimplexTeam
|
||||
invId
|
||||
cReqChatVRange@(VersionRange minV maxV)
|
||||
profile@Profile {displayName, fullName, image, contactLink, preferences}
|
||||
profile@Profile {displayName, fullName, shortDescr, image, contactLink, preferences}
|
||||
xContactId_
|
||||
welcomeMsgId_
|
||||
requestMsg_
|
||||
@@ -109,7 +109,7 @@ createOrUpdateContactRequest
|
||||
[sql|
|
||||
SELECT
|
||||
-- Contact
|
||||
ct.contact_id, ct.contact_profile_id, ct.local_display_name, ct.via_group, cp.display_name, cp.full_name, cp.image, cp.contact_link, cp.local_alias, ct.contact_used, ct.contact_status, ct.enable_ntfs, ct.send_rcpts, ct.favorite,
|
||||
ct.contact_id, ct.contact_profile_id, ct.local_display_name, ct.via_group, cp.display_name, cp.full_name, cp.short_descr, cp.image, cp.contact_link, cp.local_alias, ct.contact_used, ct.contact_status, ct.enable_ntfs, ct.send_rcpts, ct.favorite,
|
||||
cp.preferences, ct.user_preferences, ct.created_at, ct.updated_at, ct.chat_ts, ct.conn_full_link_to_connect, ct.conn_short_link_to_connect, ct.welcome_shared_msg_id, ct.request_shared_msg_id, ct.contact_request_id,
|
||||
ct.contact_group_member_id, ct.contact_grp_inv_sent, ct.ui_themes, ct.chat_deleted, ct.custom_data, ct.chat_item_ttl,
|
||||
-- Connection
|
||||
@@ -143,7 +143,7 @@ createOrUpdateContactRequest
|
||||
SELECT
|
||||
cr.contact_request_id, cr.local_display_name, cr.agent_invitation_id,
|
||||
cr.contact_id, cr.business_group_id, cr.user_contact_link_id,
|
||||
cr.contact_profile_id, p.display_name, p.full_name, p.image, p.contact_link, cr.xcontact_id,
|
||||
cr.contact_profile_id, p.display_name, p.full_name, p.short_descr, p.image, p.contact_link, cr.xcontact_id,
|
||||
cr.pq_support, cr.welcome_shared_msg_id, cr.request_shared_msg_id, p.preferences,
|
||||
cr.created_at, cr.updated_at,
|
||||
cr.peer_chat_min_version, cr.peer_chat_max_version
|
||||
@@ -161,8 +161,8 @@ createOrUpdateContactRequest
|
||||
liftIO $
|
||||
DB.execute
|
||||
db
|
||||
"INSERT INTO contact_profiles (display_name, full_name, image, contact_link, user_id, preferences, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?)"
|
||||
(displayName, fullName, image, contactLink, userId, preferences, currentTs, currentTs)
|
||||
"INSERT INTO contact_profiles (display_name, full_name, short_descr, image, contact_link, user_id, preferences, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?,?)"
|
||||
(displayName, fullName, shortDescr, image, contactLink, userId, preferences, currentTs, currentTs)
|
||||
profileId <- liftIO $ insertedRowId db
|
||||
liftIO $
|
||||
DB.execute
|
||||
@@ -229,6 +229,7 @@ createOrUpdateContactRequest
|
||||
UPDATE contact_profiles
|
||||
SET display_name = ?,
|
||||
full_name = ?,
|
||||
short_descr = ?,
|
||||
image = ?,
|
||||
contact_link = ?,
|
||||
updated_at = ?
|
||||
@@ -239,7 +240,7 @@ createOrUpdateContactRequest
|
||||
AND contact_request_id = ?
|
||||
)
|
||||
|]
|
||||
(displayName, fullName, image, contactLink, currentTs, userId, contactRequestId)
|
||||
(displayName, fullName, shortDescr, image, contactLink, currentTs, userId, contactRequestId)
|
||||
updateRequest currentTs =
|
||||
if displayName == oldDisplayName
|
||||
then
|
||||
|
||||
@@ -262,7 +262,7 @@ getContactByConnReqHash db vr user@User {userId} cReqHash1 cReqHash2 = do
|
||||
[sql|
|
||||
SELECT
|
||||
-- Contact
|
||||
ct.contact_id, ct.contact_profile_id, ct.local_display_name, ct.via_group, cp.display_name, cp.full_name, cp.image, cp.contact_link, cp.local_alias, ct.contact_used, ct.contact_status, ct.enable_ntfs, ct.send_rcpts, ct.favorite,
|
||||
ct.contact_id, ct.contact_profile_id, ct.local_display_name, ct.via_group, cp.display_name, cp.full_name, cp.short_descr, cp.image, cp.contact_link, cp.local_alias, ct.contact_used, ct.contact_status, ct.enable_ntfs, ct.send_rcpts, ct.favorite,
|
||||
cp.preferences, ct.user_preferences, ct.created_at, ct.updated_at, ct.chat_ts, ct.conn_full_link_to_connect, ct.conn_short_link_to_connect, ct.welcome_shared_msg_id, ct.request_shared_msg_id, ct.contact_request_id,
|
||||
ct.contact_group_member_id, ct.contact_grp_inv_sent, ct.ui_themes, ct.chat_deleted, ct.custom_data, ct.chat_item_ttl,
|
||||
-- Connection
|
||||
@@ -692,15 +692,15 @@ updateContactProfile_ db userId profileId profile = do
|
||||
updateContactProfile_' db userId profileId profile currentTs
|
||||
|
||||
updateContactProfile_' :: DB.Connection -> UserId -> ProfileId -> Profile -> UTCTime -> IO ()
|
||||
updateContactProfile_' db userId profileId Profile {displayName, fullName, image, contactLink, preferences} updatedAt = do
|
||||
updateContactProfile_' db userId profileId Profile {displayName, fullName, shortDescr, image, contactLink, preferences} updatedAt = do
|
||||
DB.execute
|
||||
db
|
||||
[sql|
|
||||
UPDATE contact_profiles
|
||||
SET display_name = ?, full_name = ?, image = ?, contact_link = ?, preferences = ?, updated_at = ?
|
||||
SET display_name = ?, full_name = ?, short_descr = ?, image = ?, contact_link = ?, preferences = ?, updated_at = ?
|
||||
WHERE user_id = ? AND contact_profile_id = ?
|
||||
|]
|
||||
(displayName, fullName, image, contactLink, preferences, updatedAt, userId, profileId)
|
||||
(displayName, fullName, shortDescr, image, contactLink, preferences, updatedAt, userId, profileId)
|
||||
|
||||
-- update only member profile fields (when member doesn't have associated contact - we can reset contactLink and prefs)
|
||||
updateMemberContactProfileReset_ :: DB.Connection -> UserId -> ProfileId -> Profile -> IO ()
|
||||
@@ -709,15 +709,15 @@ updateMemberContactProfileReset_ db userId profileId profile = do
|
||||
updateMemberContactProfileReset_' db userId profileId profile currentTs
|
||||
|
||||
updateMemberContactProfileReset_' :: DB.Connection -> UserId -> ProfileId -> Profile -> UTCTime -> IO ()
|
||||
updateMemberContactProfileReset_' db userId profileId Profile {displayName, fullName, image} updatedAt = do
|
||||
updateMemberContactProfileReset_' db userId profileId Profile {displayName, fullName, shortDescr, image} updatedAt = do
|
||||
DB.execute
|
||||
db
|
||||
[sql|
|
||||
UPDATE contact_profiles
|
||||
SET display_name = ?, full_name = ?, image = ?, contact_link = NULL, preferences = NULL, updated_at = ?
|
||||
SET display_name = ?, full_name = ?, short_descr = ?, image = ?, contact_link = NULL, preferences = NULL, updated_at = ?
|
||||
WHERE user_id = ? AND contact_profile_id = ?
|
||||
|]
|
||||
(displayName, fullName, image, updatedAt, userId, profileId)
|
||||
(displayName, fullName, shortDescr, image, updatedAt, userId, profileId)
|
||||
|
||||
-- update only member profile fields (when member has associated contact - we keep contactLink and prefs)
|
||||
updateMemberContactProfile_ :: DB.Connection -> UserId -> ProfileId -> Profile -> IO ()
|
||||
@@ -726,15 +726,15 @@ updateMemberContactProfile_ db userId profileId profile = do
|
||||
updateMemberContactProfile_' db userId profileId profile currentTs
|
||||
|
||||
updateMemberContactProfile_' :: DB.Connection -> UserId -> ProfileId -> Profile -> UTCTime -> IO ()
|
||||
updateMemberContactProfile_' db userId profileId Profile {displayName, fullName, image} updatedAt = do
|
||||
updateMemberContactProfile_' db userId profileId Profile {displayName, fullName, shortDescr, image} updatedAt = do
|
||||
DB.execute
|
||||
db
|
||||
[sql|
|
||||
UPDATE contact_profiles
|
||||
SET display_name = ?, full_name = ?, image = ?, updated_at = ?
|
||||
SET display_name = ?, full_name = ?, short_descr = ?, image = ?, updated_at = ?
|
||||
WHERE user_id = ? AND contact_profile_id = ?
|
||||
|]
|
||||
(displayName, fullName, image, updatedAt, userId, profileId)
|
||||
(displayName, fullName, shortDescr, image, updatedAt, userId, profileId)
|
||||
|
||||
updateContactLDN_ :: DB.Connection -> User -> Int64 -> ContactName -> ContactName -> UTCTime -> IO ()
|
||||
updateContactLDN_ db user@User {userId} contactId displayName newName updatedAt = do
|
||||
@@ -785,7 +785,7 @@ contactRequestQuery =
|
||||
SELECT
|
||||
cr.contact_request_id, cr.local_display_name, cr.agent_invitation_id,
|
||||
cr.contact_id, cr.business_group_id, cr.user_contact_link_id,
|
||||
cr.contact_profile_id, p.display_name, p.full_name, p.image, p.contact_link, cr.xcontact_id,
|
||||
cr.contact_profile_id, p.display_name, p.full_name, p.short_descr, p.image, p.contact_link, cr.xcontact_id,
|
||||
cr.pq_support, cr.welcome_shared_msg_id, cr.request_shared_msg_id, p.preferences,
|
||||
cr.created_at, cr.updated_at,
|
||||
cr.peer_chat_min_version, cr.peer_chat_max_version
|
||||
@@ -903,7 +903,7 @@ getContact_ db vr user@User {userId} contactId deleted = do
|
||||
[sql|
|
||||
SELECT
|
||||
-- Contact
|
||||
ct.contact_id, ct.contact_profile_id, ct.local_display_name, ct.via_group, cp.display_name, cp.full_name, cp.image, cp.contact_link, cp.local_alias, ct.contact_used, ct.contact_status, ct.enable_ntfs, ct.send_rcpts, ct.favorite,
|
||||
ct.contact_id, ct.contact_profile_id, ct.local_display_name, ct.via_group, cp.display_name, cp.full_name, cp.short_descr, cp.image, cp.contact_link, cp.local_alias, ct.contact_used, ct.contact_status, ct.enable_ntfs, ct.send_rcpts, ct.favorite,
|
||||
cp.preferences, ct.user_preferences, ct.created_at, ct.updated_at, ct.chat_ts, ct.conn_full_link_to_connect, ct.conn_short_link_to_connect, ct.welcome_shared_msg_id, ct.request_shared_msg_id, ct.contact_request_id,
|
||||
ct.contact_group_member_id, ct.contact_grp_inv_sent, ct.ui_themes, ct.chat_deleted, ct.custom_data, ct.chat_item_ttl,
|
||||
-- Connection
|
||||
|
||||
@@ -157,6 +157,7 @@ import Crypto.Random (ChaChaDRG)
|
||||
import qualified Data.Aeson.TH as J
|
||||
import Data.Bifunctor (second)
|
||||
import Data.Bitraversable (bitraverse)
|
||||
import Data.Char (toLower)
|
||||
import Data.Either (rights)
|
||||
import Data.Int (Int64)
|
||||
import Data.List (partition, sortOn)
|
||||
@@ -192,11 +193,11 @@ import Database.SQLite.Simple (Only (..), Query, (:.) (..))
|
||||
import Database.SQLite.Simple.QQ (sql)
|
||||
#endif
|
||||
|
||||
type MaybeGroupMemberRow = (Maybe Int64, Maybe Int64, Maybe MemberId, Maybe VersionChat, Maybe VersionChat, Maybe GroupMemberRole, Maybe GroupMemberCategory, Maybe GroupMemberStatus, Maybe BoolInt, Maybe MemberRestrictionStatus) :. (Maybe Int64, Maybe GroupMemberId, Maybe ContactName, Maybe ContactId, Maybe ProfileId, Maybe ProfileId, Maybe ContactName, Maybe Text, Maybe ImageData, Maybe ConnLinkContact, Maybe LocalAlias, Maybe Preferences) :. (Maybe UTCTime, Maybe UTCTime) :. (Maybe UTCTime, Maybe Int64, Maybe Int64, Maybe Int64, Maybe UTCTime)
|
||||
type MaybeGroupMemberRow = (Maybe Int64, Maybe Int64, Maybe MemberId, Maybe VersionChat, Maybe VersionChat, Maybe GroupMemberRole, Maybe GroupMemberCategory, Maybe GroupMemberStatus, Maybe BoolInt, Maybe MemberRestrictionStatus) :. (Maybe Int64, Maybe GroupMemberId, Maybe ContactName, Maybe ContactId, Maybe ProfileId) :. (Maybe ProfileId, Maybe ContactName, Maybe Text, Maybe Text, Maybe ImageData, Maybe ConnLinkContact, Maybe LocalAlias, Maybe Preferences) :. (Maybe UTCTime, Maybe UTCTime) :. (Maybe UTCTime, Maybe Int64, Maybe Int64, Maybe Int64, Maybe UTCTime)
|
||||
|
||||
toMaybeGroupMember :: Int64 -> MaybeGroupMemberRow -> Maybe GroupMember
|
||||
toMaybeGroupMember userContactId ((Just groupMemberId, Just groupId, Just memberId, Just minVer, Just maxVer, Just memberRole, Just memberCategory, Just memberStatus, Just showMessages, memberBlocked) :. (invitedById, invitedByGroupMemberId, Just localDisplayName, memberContactId, Just memberContactProfileId, Just profileId, Just displayName, Just fullName, image, contactLink, Just localAlias, contactPreferences) :. (Just createdAt, Just updatedAt) :. (supportChatTs, Just supportChatUnread, Just supportChatUnanswered, Just supportChatMentions, supportChatLastMsgFromMemberTs)) =
|
||||
Just $ toGroupMember userContactId ((groupMemberId, groupId, memberId, minVer, maxVer, memberRole, memberCategory, memberStatus, showMessages, memberBlocked) :. (invitedById, invitedByGroupMemberId, localDisplayName, memberContactId, memberContactProfileId, profileId, displayName, fullName, image, contactLink, localAlias, contactPreferences) :. (createdAt, updatedAt) :. (supportChatTs, supportChatUnread, supportChatUnanswered, supportChatMentions, supportChatLastMsgFromMemberTs))
|
||||
toMaybeGroupMember userContactId ((Just groupMemberId, Just groupId, Just memberId, Just minVer, Just maxVer, Just memberRole, Just memberCategory, Just memberStatus, Just showMessages, memberBlocked) :. (invitedById, invitedByGroupMemberId, Just localDisplayName, memberContactId, Just memberContactProfileId) :. (Just profileId, Just displayName, Just fullName, shortDescr, image, contactLink, Just localAlias, contactPreferences) :. (Just createdAt, Just updatedAt) :. (supportChatTs, Just supportChatUnread, Just supportChatUnanswered, Just supportChatMentions, supportChatLastMsgFromMemberTs)) =
|
||||
Just $ toGroupMember userContactId ((groupMemberId, groupId, memberId, minVer, maxVer, memberRole, memberCategory, memberStatus, showMessages, memberBlocked) :. (invitedById, invitedByGroupMemberId, localDisplayName, memberContactId, memberContactProfileId) :. (profileId, displayName, fullName, shortDescr, image, contactLink, localAlias, contactPreferences) :. (createdAt, updatedAt) :. (supportChatTs, supportChatUnread, supportChatUnanswered, supportChatMentions, supportChatLastMsgFromMemberTs))
|
||||
toMaybeGroupMember _ _ = Nothing
|
||||
|
||||
createGroupLink :: DB.Connection -> User -> GroupInfo -> ConnId -> CreatedLinkContact -> GroupLinkId -> GroupMemberRole -> SubscriptionMode -> ExceptT StoreError IO GroupLink
|
||||
@@ -317,7 +318,7 @@ setGroupLinkShortLink db gLnk@GroupLink {userContactLinkId, connLinkContact = CC
|
||||
-- | creates completely new group with a single member - the current user
|
||||
createNewGroup :: DB.Connection -> VersionRangeChat -> TVar ChaChaDRG -> User -> GroupProfile -> Maybe Profile -> ExceptT StoreError IO GroupInfo
|
||||
createNewGroup db vr gVar user@User {userId} groupProfile incognitoProfile = ExceptT $ do
|
||||
let GroupProfile {displayName, fullName, description, image, groupPreferences, memberAdmission} = groupProfile
|
||||
let GroupProfile {displayName, fullName, shortDescr, description, image, groupPreferences, memberAdmission} = groupProfile
|
||||
fullGroupPreferences = mergeGroupPreferences groupPreferences
|
||||
currentTs <- getCurrentTime
|
||||
customUserProfileId <- mapM (createIncognitoProfile_ db userId currentTs) incognitoProfile
|
||||
@@ -325,8 +326,8 @@ createNewGroup db vr gVar user@User {userId} groupProfile incognitoProfile = Exc
|
||||
groupId <- liftIO $ do
|
||||
DB.execute
|
||||
db
|
||||
"INSERT INTO group_profiles (display_name, full_name, description, image, user_id, preferences, member_admission, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?,?)"
|
||||
(displayName, fullName, description, image, userId, groupPreferences, memberAdmission, currentTs, currentTs)
|
||||
"INSERT INTO group_profiles (display_name, full_name, short_descr, description, image, user_id, preferences, member_admission, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?,?,?)"
|
||||
(displayName, fullName, shortDescr, description, image, userId, groupPreferences, memberAdmission, currentTs, currentTs)
|
||||
profileId <- insertedRowId db
|
||||
DB.execute
|
||||
db
|
||||
@@ -388,7 +389,7 @@ createGroupInvitation db vr user@User {userId} contact@Contact {contactId, activ
|
||||
DB.query db "SELECT group_id FROM groups WHERE inv_queue_info = ? AND user_id = ? LIMIT 1" (connRequest, userId)
|
||||
createGroupInvitation_ :: ExceptT StoreError IO (GroupInfo, GroupMemberId)
|
||||
createGroupInvitation_ = do
|
||||
let GroupProfile {displayName, fullName, description, image, groupPreferences, memberAdmission} = groupProfile
|
||||
let GroupProfile {displayName, fullName, shortDescr, description, image, groupPreferences, memberAdmission} = groupProfile
|
||||
fullGroupPreferences = mergeGroupPreferences groupPreferences
|
||||
ExceptT $
|
||||
withLocalDisplayName db userId displayName $ \localDisplayName -> runExceptT $ do
|
||||
@@ -396,8 +397,8 @@ createGroupInvitation db vr user@User {userId} contact@Contact {contactId, activ
|
||||
groupId <- liftIO $ do
|
||||
DB.execute
|
||||
db
|
||||
"INSERT INTO group_profiles (display_name, full_name, description, image, user_id, preferences, member_admission, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?,?)"
|
||||
(displayName, fullName, description, image, userId, groupPreferences, memberAdmission, currentTs, currentTs)
|
||||
"INSERT INTO group_profiles (display_name, full_name, short_descr, description, image, user_id, preferences, member_admission, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?,?,?)"
|
||||
(displayName, fullName, shortDescr, description, image, userId, groupPreferences, memberAdmission, currentTs, currentTs)
|
||||
profileId <- insertedRowId db
|
||||
DB.execute
|
||||
db
|
||||
@@ -753,13 +754,13 @@ createGroupViaLink'
|
||||
|
||||
createGroup_ :: DB.Connection -> UserId -> GroupProfile -> Maybe (CreatedLinkContact, Maybe SharedMsgId) -> Maybe BusinessChatInfo -> UTCTime -> ExceptT StoreError IO (GroupId, Text)
|
||||
createGroup_ db userId groupProfile prepared business currentTs = ExceptT $ do
|
||||
let GroupProfile {displayName, fullName, description, image, groupPreferences, memberAdmission} = groupProfile
|
||||
let GroupProfile {displayName, fullName, shortDescr, description, image, groupPreferences, memberAdmission} = groupProfile
|
||||
withLocalDisplayName db userId displayName $ \localDisplayName -> runExceptT $ do
|
||||
liftIO $ do
|
||||
DB.execute
|
||||
db
|
||||
"INSERT INTO group_profiles (display_name, full_name, description, image, user_id, preferences, member_admission, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?,?)"
|
||||
(displayName, fullName, description, image, userId, groupPreferences, memberAdmission, currentTs, currentTs)
|
||||
"INSERT INTO group_profiles (display_name, full_name, short_descr, description, image, user_id, preferences, member_admission, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?,?,?)"
|
||||
(displayName, fullName, shortDescr, description, image, userId, groupPreferences, memberAdmission, currentTs, currentTs)
|
||||
profileId <- insertedRowId db
|
||||
DB.execute
|
||||
db
|
||||
@@ -936,14 +937,14 @@ getUserGroupDetails db vr User {userId, userContactId} _contactId_ search_ = do
|
||||
db
|
||||
[sql|
|
||||
SELECT
|
||||
g.group_id, g.local_display_name, gp.display_name, gp.full_name, g.local_alias, gp.description, gp.image,
|
||||
g.group_id, g.local_display_name, gp.display_name, gp.full_name, gp.short_descr, g.local_alias, gp.description, gp.image,
|
||||
g.enable_ntfs, g.send_rcpts, g.favorite, gp.preferences, gp.member_admission,
|
||||
g.created_at, g.updated_at, g.chat_ts, g.user_member_profile_sent_at,
|
||||
g.conn_full_link_to_connect, g.conn_short_link_to_connect, g.conn_link_prepared_connection, g.conn_link_started_connection, g.welcome_shared_msg_id, g.request_shared_msg_id,
|
||||
g.business_chat, g.business_member_id, g.customer_member_id,
|
||||
g.ui_themes, g.custom_data, g.chat_item_ttl, g.members_require_attention,
|
||||
mu.group_member_id, g.group_id, mu.member_id, mu.peer_chat_min_version, mu.peer_chat_max_version, mu.member_role, mu.member_category, mu.member_status, mu.show_messages, mu.member_restriction,
|
||||
mu.invited_by, mu.invited_by_group_member_id, mu.local_display_name, mu.contact_id, mu.contact_profile_id, pu.contact_profile_id, pu.display_name, pu.full_name, pu.image, pu.contact_link, pu.local_alias, pu.preferences,
|
||||
mu.invited_by, mu.invited_by_group_member_id, mu.local_display_name, mu.contact_id, mu.contact_profile_id, pu.contact_profile_id, pu.display_name, pu.full_name, pu.short_descr, pu.image, pu.contact_link, pu.local_alias, pu.preferences,
|
||||
mu.created_at, mu.updated_at,
|
||||
mu.support_chat_ts, mu.support_chat_items_unread, mu.support_chat_items_member_attention, mu.support_chat_items_mentions, mu.support_chat_last_msg_from_member_ts
|
||||
FROM groups g
|
||||
@@ -951,15 +952,16 @@ getUserGroupDetails db vr User {userId, userContactId} _contactId_ search_ = do
|
||||
JOIN group_members mu USING (group_id)
|
||||
JOIN contact_profiles pu ON pu.contact_profile_id = COALESCE(mu.member_profile_id, mu.contact_profile_id)
|
||||
WHERE g.user_id = ? AND mu.contact_id = ?
|
||||
AND (LOWER(gp.display_name) LIKE '%' || LOWER(?) || '%'
|
||||
OR LOWER(gp.full_name) LIKE '%' || LOWER(?) || '%'
|
||||
OR LOWER(gp.description) LIKE '%' || LOWER(?) || '%'
|
||||
AND (LOWER(gp.display_name) LIKE '%' || ? || '%'
|
||||
OR LOWER(gp.full_name) LIKE '%' || ? || '%'
|
||||
OR LOWER(gp.short_descr) LIKE '%' || ? || '%'
|
||||
OR LOWER(gp.description) LIKE '%' || ? || '%'
|
||||
)
|
||||
|]
|
||||
(userId, userContactId, search, search, search)
|
||||
(userId, userContactId, search, search, search, search)
|
||||
mapM (addGroupChatTags db) g_
|
||||
where
|
||||
search = fromMaybe "" search_
|
||||
search = maybe "" (map toLower) search_
|
||||
|
||||
getUserGroupsWithSummary :: DB.Connection -> VersionRangeChat -> User -> Maybe ContactId -> Maybe String -> IO [(GroupInfo, GroupSummary)]
|
||||
getUserGroupsWithSummary db vr user _contactId_ search_ =
|
||||
@@ -1008,7 +1010,7 @@ groupMemberQuery =
|
||||
[sql|
|
||||
SELECT
|
||||
m.group_member_id, m.group_id, m.member_id, m.peer_chat_min_version, m.peer_chat_max_version, m.member_role, m.member_category, m.member_status, m.show_messages, m.member_restriction,
|
||||
m.invited_by, m.invited_by_group_member_id, m.local_display_name, m.contact_id, m.contact_profile_id, p.contact_profile_id, p.display_name, p.full_name, p.image, p.contact_link, p.local_alias, p.preferences,
|
||||
m.invited_by, m.invited_by_group_member_id, m.local_display_name, m.contact_id, m.contact_profile_id, p.contact_profile_id, p.display_name, p.full_name, p.short_descr, p.image, p.contact_link, p.local_alias, p.preferences,
|
||||
m.created_at, m.updated_at,
|
||||
m.support_chat_ts, m.support_chat_items_unread, m.support_chat_items_member_attention, m.support_chat_items_mentions, m.support_chat_last_msg_from_member_ts,
|
||||
c.connection_id, c.agent_conn_id, c.conn_level, c.via_contact, c.via_user_contact_link, c.via_group_link, c.group_link_id, c.xcontact_id, c.custom_user_profile_id,
|
||||
@@ -1239,7 +1241,7 @@ createJoiningMember
|
||||
User {userId, userContactId}
|
||||
GroupInfo {groupId, membership}
|
||||
cReqChatVRange
|
||||
Profile {displayName, fullName, image, contactLink, preferences}
|
||||
Profile {displayName, fullName, shortDescr, image, contactLink, preferences}
|
||||
cReqXContactId_
|
||||
welcomeMsgId_
|
||||
memberRole
|
||||
@@ -1249,8 +1251,8 @@ createJoiningMember
|
||||
liftIO $
|
||||
DB.execute
|
||||
db
|
||||
"INSERT INTO contact_profiles (display_name, full_name, image, contact_link, user_id, preferences, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?)"
|
||||
(displayName, fullName, image, contactLink, userId, preferences, currentTs, currentTs)
|
||||
"INSERT INTO contact_profiles (display_name, full_name, short_descr, image, contact_link, user_id, preferences, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?,?)"
|
||||
(displayName, fullName, shortDescr, image, contactLink, userId, preferences, currentTs, currentTs)
|
||||
profileId <- liftIO $ insertedRowId db
|
||||
createWithRandomId gVar $ \memId -> do
|
||||
insertMember_ ldn profileId (MemberId memId) currentTs
|
||||
@@ -1299,7 +1301,7 @@ createBusinessRequestGroup
|
||||
gVar
|
||||
user@User {userId, userContactId}
|
||||
cReqChatVRange
|
||||
Profile {displayName, fullName, image}
|
||||
Profile {displayName, fullName, shortDescr, image}
|
||||
profileId -- contact request profile id, to be used for member profile
|
||||
ldn -- contact request local display name, to be used for group local display name
|
||||
groupPreferences = do
|
||||
@@ -1315,8 +1317,8 @@ createBusinessRequestGroup
|
||||
liftIO $
|
||||
DB.execute
|
||||
db
|
||||
"INSERT INTO group_profiles (display_name, full_name, image, user_id, preferences, created_at, updated_at) VALUES (?,?,?,?,?,?,?)"
|
||||
(displayName, fullName, image, userId, groupPreferences, currentTs, currentTs)
|
||||
"INSERT INTO group_profiles (display_name, full_name, short_descr, image, user_id, preferences, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?)"
|
||||
(displayName, fullName, shortDescr, image, userId, groupPreferences, currentTs, currentTs)
|
||||
groupProfileId <- liftIO $ insertedRowId db
|
||||
liftIO $
|
||||
DB.execute
|
||||
@@ -1503,12 +1505,12 @@ createNewGroupMember db user gInfo invitingMember memInfo@MemberInfo {profile} m
|
||||
liftIO $ createNewMember_ db user gInfo newMember currentTs
|
||||
|
||||
createNewMemberProfile_ :: DB.Connection -> User -> Profile -> UTCTime -> ExceptT StoreError IO (Text, ProfileId)
|
||||
createNewMemberProfile_ db User {userId} Profile {displayName, fullName, image, contactLink, preferences} createdAt =
|
||||
createNewMemberProfile_ db User {userId} Profile {displayName, fullName, shortDescr, image, contactLink, preferences} createdAt =
|
||||
ExceptT . withLocalDisplayName db userId displayName $ \ldn -> do
|
||||
DB.execute
|
||||
db
|
||||
"INSERT INTO contact_profiles (display_name, full_name, image, contact_link, user_id, preferences, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?)"
|
||||
(displayName, fullName, image, contactLink, userId, preferences, createdAt, createdAt)
|
||||
"INSERT INTO contact_profiles (display_name, full_name, short_descr, image, contact_link, user_id, preferences, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?,?)"
|
||||
(displayName, fullName, shortDescr, image, contactLink, userId, preferences, createdAt, createdAt)
|
||||
profileId <- insertedRowId db
|
||||
pure $ Right (ldn, profileId)
|
||||
|
||||
@@ -1818,7 +1820,7 @@ getViaGroupMember db vr User {userId, userContactId} Contact {contactId} = do
|
||||
[sql|
|
||||
SELECT
|
||||
-- GroupInfo
|
||||
g.group_id, g.local_display_name, gp.display_name, gp.full_name, g.local_alias, gp.description, gp.image,
|
||||
g.group_id, g.local_display_name, gp.display_name, gp.full_name, gp.short_descr, g.local_alias, gp.description, gp.image,
|
||||
g.enable_ntfs, g.send_rcpts, g.favorite, gp.preferences, gp.member_admission,
|
||||
g.created_at, g.updated_at, g.chat_ts, g.user_member_profile_sent_at,
|
||||
g.conn_full_link_to_connect, g.conn_short_link_to_connect, g.conn_link_prepared_connection, g.conn_link_started_connection, g.welcome_shared_msg_id, g.request_shared_msg_id,
|
||||
@@ -1828,12 +1830,12 @@ getViaGroupMember db vr User {userId, userContactId} Contact {contactId} = do
|
||||
mu.group_member_id, mu.group_id, mu.member_id, mu.peer_chat_min_version, mu.peer_chat_max_version, mu.member_role, mu.member_category,
|
||||
mu.member_status, mu.show_messages, mu.member_restriction, mu.invited_by, mu.invited_by_group_member_id, mu.local_display_name, mu.contact_id, mu.contact_profile_id, pu.contact_profile_id,
|
||||
-- GroupInfo {membership = GroupMember {memberProfile}}
|
||||
pu.display_name, pu.full_name, pu.image, pu.contact_link, pu.local_alias, pu.preferences,
|
||||
pu.display_name, pu.full_name, pu.short_descr, pu.image, pu.contact_link, pu.local_alias, pu.preferences,
|
||||
mu.created_at, mu.updated_at,
|
||||
mu.support_chat_ts, mu.support_chat_items_unread, mu.support_chat_items_member_attention, mu.support_chat_items_mentions, mu.support_chat_last_msg_from_member_ts,
|
||||
-- via GroupMember
|
||||
m.group_member_id, m.group_id, m.member_id, m.peer_chat_min_version, m.peer_chat_max_version, m.member_role, m.member_category, m.member_status, m.show_messages, m.member_restriction,
|
||||
m.invited_by, m.invited_by_group_member_id, m.local_display_name, m.contact_id, m.contact_profile_id, p.contact_profile_id, p.display_name, p.full_name, p.image, p.contact_link, p.local_alias, p.preferences,
|
||||
m.invited_by, m.invited_by_group_member_id, m.local_display_name, m.contact_id, m.contact_profile_id, p.contact_profile_id, p.display_name, p.full_name, p.short_descr, p.image, p.contact_link, p.local_alias, p.preferences,
|
||||
m.created_at, m.updated_at,
|
||||
m.support_chat_ts, m.support_chat_items_unread, m.support_chat_items_member_attention, m.support_chat_items_mentions, m.support_chat_last_msg_from_member_ts,
|
||||
c.connection_id, c.agent_conn_id, c.conn_level, c.via_contact, c.via_user_contact_link, c.via_group_link, c.group_link_id, c.xcontact_id, c.custom_user_profile_id,
|
||||
@@ -1881,7 +1883,7 @@ getViaGroupContact db vr user@User {userId} GroupMember {groupMemberId} = do
|
||||
maybe (pure Nothing) (fmap eitherToMaybe . runExceptT . getContact db vr user) contactId_
|
||||
|
||||
updateGroupProfile :: DB.Connection -> User -> GroupInfo -> GroupProfile -> ExceptT StoreError IO GroupInfo
|
||||
updateGroupProfile db user@User {userId} g@GroupInfo {groupId, localDisplayName, groupProfile = GroupProfile {displayName}} p'@GroupProfile {displayName = newName, fullName, description, image, groupPreferences, memberAdmission}
|
||||
updateGroupProfile db user@User {userId} g@GroupInfo {groupId, localDisplayName, groupProfile = GroupProfile {displayName}} p'@GroupProfile {displayName = newName, fullName, shortDescr, description, image, groupPreferences, memberAdmission}
|
||||
| displayName == newName = liftIO $ do
|
||||
currentTs <- getCurrentTime
|
||||
updateGroupProfile_ currentTs
|
||||
@@ -1899,14 +1901,14 @@ updateGroupProfile db user@User {userId} g@GroupInfo {groupId, localDisplayName,
|
||||
db
|
||||
[sql|
|
||||
UPDATE group_profiles
|
||||
SET display_name = ?, full_name = ?, description = ?, image = ?, preferences = ?, member_admission = ?, updated_at = ?
|
||||
SET display_name = ?, full_name = ?, short_descr = ?, description = ?, image = ?, preferences = ?, member_admission = ?, updated_at = ?
|
||||
WHERE group_profile_id IN (
|
||||
SELECT group_profile_id
|
||||
FROM groups
|
||||
WHERE user_id = ? AND group_id = ?
|
||||
)
|
||||
|]
|
||||
(newName, fullName, description, image, groupPreferences, memberAdmission, currentTs, userId, groupId)
|
||||
(newName, fullName, shortDescr, description, image, groupPreferences, memberAdmission, currentTs, userId, groupId)
|
||||
updateGroup_ ldn currentTs = do
|
||||
DB.execute
|
||||
db
|
||||
@@ -1932,10 +1934,10 @@ updateGroupPreferences db User {userId} g@GroupInfo {groupId, groupProfile = p}
|
||||
pure (g :: GroupInfo) {groupProfile = p {groupPreferences = Just ps}, fullGroupPreferences = mergeGroupPreferences $ Just ps}
|
||||
|
||||
updateGroupProfileFromMember :: DB.Connection -> User -> GroupInfo -> Profile -> ExceptT StoreError IO GroupInfo
|
||||
updateGroupProfileFromMember db user g@GroupInfo {groupId} Profile {displayName = n, fullName = fn, image = img} = do
|
||||
updateGroupProfileFromMember db user g@GroupInfo {groupId} Profile {displayName = n, fullName = fn, shortDescr = sd, image = img} = do
|
||||
p <- getGroupProfile -- to avoid any race conditions with UI
|
||||
let g' = g {groupProfile = p} :: GroupInfo
|
||||
p' = p {displayName = n, fullName = fn, image = img} :: GroupProfile
|
||||
p' = p {displayName = n, fullName = fn, shortDescr = sd, image = img} :: GroupProfile
|
||||
updateGroupProfile db user g' p'
|
||||
where
|
||||
getGroupProfile =
|
||||
@@ -1944,14 +1946,14 @@ updateGroupProfileFromMember db user g@GroupInfo {groupId} Profile {displayName
|
||||
DB.query
|
||||
db
|
||||
[sql|
|
||||
SELECT gp.display_name, gp.full_name, gp.description, gp.image, gp.preferences, gp.member_admission
|
||||
SELECT gp.display_name, gp.full_name, gp.short_descr, gp.description, gp.image, gp.preferences, gp.member_admission
|
||||
FROM group_profiles gp
|
||||
JOIN groups g ON gp.group_profile_id = g.group_profile_id
|
||||
WHERE g.group_id = ?
|
||||
|]
|
||||
(Only groupId)
|
||||
toGroupProfile (displayName, fullName, description, image, groupPreferences, memberAdmission) =
|
||||
GroupProfile {displayName, fullName, description, image, groupPreferences, memberAdmission}
|
||||
toGroupProfile (displayName, fullName, shortDescr, description, image, groupPreferences, memberAdmission) =
|
||||
GroupProfile {displayName, fullName, shortDescr, description, image, groupPreferences, memberAdmission}
|
||||
|
||||
getGroupInfo :: DB.Connection -> VersionRangeChat -> User -> Int64 -> ExceptT StoreError IO GroupInfo
|
||||
getGroupInfo db vr User {userId, userContactId} groupId = ExceptT $ do
|
||||
@@ -2052,11 +2054,8 @@ getActiveMembersByName db vr user@User {userId} groupMemberName = do
|
||||
ts GroupInfo {chatTs, updatedAt} = fromMaybe updatedAt chatTs
|
||||
|
||||
getMatchingContacts :: DB.Connection -> VersionRangeChat -> User -> Contact -> IO [Contact]
|
||||
getMatchingContacts db vr user@User {userId} Contact {contactId, profile = LocalProfile {displayName, fullName, image}} = do
|
||||
contactIds <-
|
||||
map fromOnly <$> case image of
|
||||
Just img -> DB.query db (q <> " AND p.image = ?") (userId, contactId, CSActive, displayName, fullName, img)
|
||||
Nothing -> DB.query db (q <> " AND p.image is NULL") (userId, contactId, CSActive, displayName, fullName)
|
||||
getMatchingContacts db vr user@User {userId} Contact {contactId, profile = LocalProfile {displayName, fullName, shortDescr, image}} = do
|
||||
contactIds <- map fromOnly <$> DB.query db q (userId, contactId, CSActive, displayName, fullName, shortDescr, image)
|
||||
rights <$> mapM (runExceptT . getContact db vr user) contactIds
|
||||
where
|
||||
-- this query is different from one in getMatchingMemberContacts
|
||||
@@ -2069,14 +2068,12 @@ getMatchingContacts db vr user@User {userId} Contact {contactId, profile = Local
|
||||
WHERE ct.user_id = ? AND ct.contact_id != ?
|
||||
AND ct.contact_status = ? AND ct.deleted = 0 AND ct.is_user = 0
|
||||
AND p.display_name = ? AND p.full_name = ?
|
||||
AND p.short_descr IS ? AND p.image IS ?
|
||||
|]
|
||||
|
||||
getMatchingMembers :: DB.Connection -> VersionRangeChat -> User -> Contact -> IO [GroupMember]
|
||||
getMatchingMembers db vr user@User {userId} Contact {profile = LocalProfile {displayName, fullName, image}} = do
|
||||
memberIds <-
|
||||
map fromOnly <$> case image of
|
||||
Just img -> DB.query db (q <> " AND p.image = ?") (userId, GCUserMember, displayName, fullName, img)
|
||||
Nothing -> DB.query db (q <> " AND p.image is NULL") (userId, GCUserMember, displayName, fullName)
|
||||
getMatchingMembers db vr user@User {userId} Contact {profile = LocalProfile {displayName, fullName, shortDescr, image}} = do
|
||||
memberIds <- map fromOnly <$> DB.query db q (userId, GCUserMember, displayName, fullName, shortDescr, image)
|
||||
filter memberCurrent . rights <$> mapM (runExceptT . getGroupMemberById db vr user) memberIds
|
||||
where
|
||||
-- only match with members without associated contact
|
||||
@@ -2088,15 +2085,13 @@ getMatchingMembers db vr user@User {userId} Contact {profile = LocalProfile {dis
|
||||
WHERE m.user_id = ? AND m.contact_id IS NULL
|
||||
AND m.member_category != ?
|
||||
AND p.display_name = ? AND p.full_name = ?
|
||||
AND p.short_descr IS ? AND p.image IS ?
|
||||
|]
|
||||
|
||||
getMatchingMemberContacts :: DB.Connection -> VersionRangeChat -> User -> GroupMember -> IO [Contact]
|
||||
getMatchingMemberContacts _ _ _ GroupMember {memberContactId = Just _} = pure []
|
||||
getMatchingMemberContacts db vr user@User {userId} GroupMember {memberProfile = LocalProfile {displayName, fullName, image}} = do
|
||||
contactIds <-
|
||||
map fromOnly <$> case image of
|
||||
Just img -> DB.query db (q <> " AND p.image = ?") (userId, CSActive, displayName, fullName, img)
|
||||
Nothing -> DB.query db (q <> " AND p.image is NULL") (userId, CSActive, displayName, fullName)
|
||||
getMatchingMemberContacts db vr user@User {userId} GroupMember {memberProfile = LocalProfile {displayName, fullName, shortDescr, image}} = do
|
||||
contactIds <- map fromOnly <$> DB.query db q (userId, CSActive, displayName, fullName, shortDescr, image)
|
||||
rights <$> mapM (runExceptT . getContact db vr user) contactIds
|
||||
where
|
||||
q =
|
||||
@@ -2107,6 +2102,7 @@ getMatchingMemberContacts db vr user@User {userId} GroupMember {memberProfile =
|
||||
WHERE ct.user_id = ?
|
||||
AND ct.contact_status = ? AND ct.deleted = 0 AND ct.is_user = 0
|
||||
AND p.display_name = ? AND p.full_name = ?
|
||||
AND p.short_descr IS ? AND p.image IS ?
|
||||
|]
|
||||
|
||||
createSentProbe :: DB.Connection -> TVar ChaChaDRG -> UserId -> ContactOrMember -> ExceptT StoreError IO (Probe, Int64)
|
||||
|
||||
@@ -144,6 +144,7 @@ import Control.Monad.IO.Class
|
||||
import Crypto.Random (ChaChaDRG)
|
||||
import Data.Bifunctor (first)
|
||||
import Data.ByteString.Char8 (ByteString)
|
||||
import Data.Char (toLower)
|
||||
import Data.Either (fromRight, rights)
|
||||
import Data.Int (Int64)
|
||||
import Data.List (foldl', sortBy)
|
||||
@@ -646,7 +647,7 @@ getChatItemQuote_ db User {userId, userContactId} chatDirection QuotedMsg {msgRe
|
||||
-- GroupMember
|
||||
m.group_member_id, m.group_id, m.member_id, m.peer_chat_min_version, m.peer_chat_max_version, m.member_role, m.member_category,
|
||||
m.member_status, m.show_messages, m.member_restriction, m.invited_by, m.invited_by_group_member_id, m.local_display_name, m.contact_id, m.contact_profile_id, p.contact_profile_id,
|
||||
p.display_name, p.full_name, p.image, p.contact_link, p.local_alias, p.preferences,
|
||||
p.display_name, p.full_name, p.short_descr, p.image, p.contact_link, p.local_alias, p.preferences,
|
||||
m.created_at, m.updated_at,
|
||||
m.support_chat_ts, m.support_chat_items_unread, m.support_chat_items_member_attention, m.support_chat_items_mentions, m.support_chat_last_msg_from_member_ts
|
||||
FROM group_members m
|
||||
@@ -789,13 +790,15 @@ findDirectChatPreviews_ db User {userId} pagination clq =
|
||||
JOIN contact_profiles cp ON ct.contact_profile_id = cp.contact_profile_id
|
||||
WHERE ct.user_id = ? AND ct.is_user = 0 AND ct.deleted = 0 AND ct.contact_used = 1
|
||||
AND (
|
||||
LOWER(ct.local_display_name) LIKE '%' || LOWER(?) || '%'
|
||||
OR LOWER(cp.display_name) LIKE '%' || LOWER(?) || '%'
|
||||
OR LOWER(cp.full_name) LIKE '%' || LOWER(?) || '%'
|
||||
OR LOWER(cp.local_alias) LIKE '%' || LOWER(?) || '%'
|
||||
LOWER(ct.local_display_name) LIKE '%' || ? || '%'
|
||||
OR LOWER(cp.display_name) LIKE '%' || ? || '%'
|
||||
OR LOWER(cp.full_name) LIKE '%' || ? || '%'
|
||||
OR LOWER(cp.short_descr) LIKE '%' || ? || '%'
|
||||
OR LOWER(cp.local_alias) LIKE '%' || ? || '%'
|
||||
)
|
||||
|]
|
||||
p = baseParams :. (userId, search, search, search, search)
|
||||
s = map toLower search
|
||||
p = baseParams :. (userId, s, s, s, s, s)
|
||||
queryWithPagination q p
|
||||
queryWithPagination :: ToRow p => Query -> p -> IO [(ContactId, UTCTime, Maybe ChatItemId) :. ChatStatsRow]
|
||||
queryWithPagination query params = case pagination of
|
||||
@@ -895,13 +898,15 @@ findGroupChatPreviews_ db User {userId} pagination clq =
|
||||
JOIN group_profiles gp ON gp.group_profile_id = g.group_profile_id
|
||||
WHERE g.user_id = ?
|
||||
AND (
|
||||
LOWER(g.local_display_name) LIKE '%' || LOWER(?) || '%'
|
||||
OR LOWER(gp.display_name) LIKE '%' || LOWER(?) || '%'
|
||||
OR LOWER(gp.full_name) LIKE '%' || LOWER(?) || '%'
|
||||
OR LOWER(gp.description) LIKE '%' || LOWER(?) || '%'
|
||||
LOWER(g.local_display_name) LIKE '%' || ? || '%'
|
||||
OR LOWER(gp.display_name) LIKE '%' || ? || '%'
|
||||
OR LOWER(gp.full_name) LIKE '%' || ? || '%'
|
||||
OR LOWER(gp.short_descr) LIKE '%' || ? || '%'
|
||||
OR LOWER(gp.description) LIKE '%' || ? || '%'
|
||||
)
|
||||
|]
|
||||
p = baseParams :. (userId, search, search, search, search)
|
||||
s = map toLower search
|
||||
p = baseParams :. (userId, s, s, s, s, s)
|
||||
queryWithPagination q p
|
||||
queryWithPagination :: ToRow p => Query -> p -> IO [(GroupId, UTCTime, Maybe ChatItemId) :. GroupStatsRow]
|
||||
queryWithPagination query params = case pagination of
|
||||
@@ -1051,7 +1056,7 @@ getContactRequestChatPreviews_ db User {userId} pagination clq = case clq of
|
||||
SELECT
|
||||
cr.contact_request_id, cr.local_display_name, cr.agent_invitation_id,
|
||||
cr.contact_id, cr.business_group_id, cr.user_contact_link_id,
|
||||
cr.contact_profile_id, p.display_name, p.full_name, p.image, p.contact_link, cr.xcontact_id,
|
||||
cr.contact_profile_id, p.display_name, p.full_name, p.short_descr, p.image, p.contact_link, cr.xcontact_id,
|
||||
cr.pq_support, cr.welcome_shared_msg_id, cr.request_shared_msg_id, p.preferences,
|
||||
cr.created_at, cr.updated_at,
|
||||
cr.peer_chat_min_version, cr.peer_chat_max_version
|
||||
@@ -1065,12 +1070,13 @@ getContactRequestChatPreviews_ db User {userId} pagination clq = case clq of
|
||||
AND cr.contact_id IS NULL
|
||||
AND cr.business_group_id IS NULL
|
||||
AND (
|
||||
LOWER(cr.local_display_name) LIKE '%' || LOWER(?) || '%'
|
||||
OR LOWER(p.display_name) LIKE '%' || LOWER(?) || '%'
|
||||
OR LOWER(p.full_name) LIKE '%' || LOWER(?) || '%'
|
||||
LOWER(cr.local_display_name) LIKE '%' || ? || '%'
|
||||
OR LOWER(p.display_name) LIKE '%' || ? || '%'
|
||||
OR LOWER(p.full_name) LIKE '%' || ? || '%'
|
||||
OR LOWER(p.short_descr) LIKE '%' || ? || '%'
|
||||
)
|
||||
|]
|
||||
params search = (userId, userId, search, search, search)
|
||||
params search = let s = map toLower search in (userId, userId, s, s, s, s)
|
||||
getPreviews search = case pagination of
|
||||
PTLast count -> DB.query db (query <> " ORDER BY cr.updated_at DESC LIMIT ?") (params search :. Only count)
|
||||
PTAfter ts count -> DB.query db (query <> " AND cr.updated_at > ? ORDER BY cr.updated_at ASC LIMIT ?") (params search :. (ts, count))
|
||||
@@ -2896,7 +2902,7 @@ getGroupChatItem db User {userId, userContactId} groupId itemId = ExceptT $ do
|
||||
-- GroupMember
|
||||
m.group_member_id, m.group_id, m.member_id, m.peer_chat_min_version, m.peer_chat_max_version, m.member_role, m.member_category,
|
||||
m.member_status, m.show_messages, m.member_restriction, m.invited_by, m.invited_by_group_member_id, m.local_display_name, m.contact_id, m.contact_profile_id, p.contact_profile_id,
|
||||
p.display_name, p.full_name, p.image, p.contact_link, p.local_alias, p.preferences,
|
||||
p.display_name, p.full_name, p.short_descr, p.image, p.contact_link, p.local_alias, p.preferences,
|
||||
m.created_at, m.updated_at,
|
||||
m.support_chat_ts, m.support_chat_items_unread, m.support_chat_items_member_attention, m.support_chat_items_mentions, m.support_chat_last_msg_from_member_ts,
|
||||
-- quoted ChatItem
|
||||
@@ -2904,13 +2910,13 @@ getGroupChatItem db User {userId, userContactId} groupId itemId = ExceptT $ do
|
||||
-- quoted GroupMember
|
||||
rm.group_member_id, rm.group_id, rm.member_id, rm.peer_chat_min_version, rm.peer_chat_max_version, rm.member_role, rm.member_category,
|
||||
rm.member_status, rm.show_messages, rm.member_restriction, rm.invited_by, rm.invited_by_group_member_id, rm.local_display_name, rm.contact_id, rm.contact_profile_id, rp.contact_profile_id,
|
||||
rp.display_name, rp.full_name, rp.image, rp.contact_link, rp.local_alias, rp.preferences,
|
||||
rp.display_name, rp.full_name, rp.short_descr, rp.image, rp.contact_link, rp.local_alias, rp.preferences,
|
||||
rm.created_at, rm.updated_at,
|
||||
rm.support_chat_ts, rm.support_chat_items_unread, rm.support_chat_items_member_attention, rm.support_chat_items_mentions, rm.support_chat_last_msg_from_member_ts,
|
||||
-- deleted by GroupMember
|
||||
dbm.group_member_id, dbm.group_id, dbm.member_id, dbm.peer_chat_min_version, dbm.peer_chat_max_version, dbm.member_role, dbm.member_category,
|
||||
dbm.member_status, dbm.show_messages, dbm.member_restriction, dbm.invited_by, dbm.invited_by_group_member_id, dbm.local_display_name, dbm.contact_id, dbm.contact_profile_id, dbp.contact_profile_id,
|
||||
dbp.display_name, dbp.full_name, dbp.image, dbp.contact_link, dbp.local_alias, dbp.preferences,
|
||||
dbp.display_name, dbp.full_name, dbp.short_descr, dbp.image, dbp.contact_link, dbp.local_alias, dbp.preferences,
|
||||
dbm.created_at, dbm.updated_at,
|
||||
dbm.support_chat_ts, dbm.support_chat_items_unread, dbm.support_chat_items_member_attention, dbm.support_chat_items_mentions, dbm.support_chat_last_msg_from_member_ts
|
||||
FROM chat_items i
|
||||
|
||||
@@ -11,6 +11,7 @@ import Simplex.Chat.Store.Postgres.Migrations.M20250513_group_scope
|
||||
import Simplex.Chat.Store.Postgres.Migrations.M20250526_short_links
|
||||
import Simplex.Chat.Store.Postgres.Migrations.M20250702_contact_requests_remove_cascade_delete
|
||||
import Simplex.Chat.Store.Postgres.Migrations.M20250704_groups_conn_link_prepared_connection
|
||||
import Simplex.Chat.Store.Postgres.Migrations.M20250709_profile_short_descr
|
||||
import Simplex.Messaging.Agent.Store.Shared (Migration (..))
|
||||
|
||||
schemaMigrations :: [(String, Text, Maybe Text)]
|
||||
@@ -21,7 +22,8 @@ schemaMigrations =
|
||||
("20250513_group_scope", m20250513_group_scope, Just down_m20250513_group_scope),
|
||||
("20250526_short_links", m20250526_short_links, Just down_m20250526_short_links),
|
||||
("20250702_contact_requests_remove_cascade_delete", m20250702_contact_requests_remove_cascade_delete, Just down_m20250702_contact_requests_remove_cascade_delete),
|
||||
("20250704_groups_conn_link_prepared_connection", m20250704_groups_conn_link_prepared_connection, Just down_m20250704_groups_conn_link_prepared_connection)
|
||||
("20250704_groups_conn_link_prepared_connection", m20250704_groups_conn_link_prepared_connection, Just down_m20250704_groups_conn_link_prepared_connection),
|
||||
("20250709_profile_short_descr", m20250709_profile_short_descr, Just down_m20250709_profile_short_descr)
|
||||
]
|
||||
|
||||
-- | The list of migrations in ascending order by date
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
{-# LANGUAGE QuasiQuotes #-}
|
||||
|
||||
module Simplex.Chat.Store.Postgres.Migrations.M20250709_profile_short_descr where
|
||||
|
||||
import Data.Text (Text)
|
||||
import qualified Data.Text as T
|
||||
import Text.RawString.QQ (r)
|
||||
|
||||
m20250709_profile_short_descr :: Text
|
||||
m20250709_profile_short_descr =
|
||||
T.pack
|
||||
[r|
|
||||
ALTER TABLE contact_profiles ADD COLUMN short_descr TEXT;
|
||||
ALTER TABLE group_profiles ADD COLUMN short_descr TEXT;
|
||||
|]
|
||||
|
||||
down_m20250709_profile_short_descr :: Text
|
||||
down_m20250709_profile_short_descr =
|
||||
T.pack
|
||||
[r|
|
||||
ALTER TABLE contact_profiles DROP COLUMN short_descr;
|
||||
ALTER TABLE group_profiles DROP COLUMN short_descr;
|
||||
|]
|
||||
@@ -331,7 +331,8 @@ CREATE TABLE test_chat_schema.contact_profiles (
|
||||
incognito smallint,
|
||||
local_alias text DEFAULT ''::text NOT NULL,
|
||||
preferences text,
|
||||
contact_link bytea
|
||||
contact_link bytea,
|
||||
short_descr text
|
||||
);
|
||||
|
||||
|
||||
@@ -577,7 +578,8 @@ CREATE TABLE test_chat_schema.group_profiles (
|
||||
user_id bigint,
|
||||
preferences text,
|
||||
description text,
|
||||
member_admission text
|
||||
member_admission text,
|
||||
short_descr text
|
||||
);
|
||||
|
||||
|
||||
|
||||
@@ -129,7 +129,7 @@ createUserRecord :: DB.Connection -> AgentUserId -> Profile -> Bool -> ExceptT S
|
||||
createUserRecord db auId p activeUser = createUserRecordAt db auId p activeUser =<< liftIO getCurrentTime
|
||||
|
||||
createUserRecordAt :: DB.Connection -> AgentUserId -> Profile -> Bool -> UTCTime -> ExceptT StoreError IO User
|
||||
createUserRecordAt db (AgentUserId auId) Profile {displayName, fullName, image, preferences = userPreferences} activeUser currentTs =
|
||||
createUserRecordAt db (AgentUserId auId) Profile {displayName, fullName, shortDescr, image, preferences = userPreferences} activeUser currentTs =
|
||||
checkConstraint SEDuplicateName . liftIO $ do
|
||||
when activeUser $ DB.execute_ db "UPDATE users SET active_user = 0"
|
||||
let showNtfs = True
|
||||
@@ -147,8 +147,8 @@ createUserRecordAt db (AgentUserId auId) Profile {displayName, fullName, image,
|
||||
(displayName, displayName, userId, currentTs, currentTs)
|
||||
DB.execute
|
||||
db
|
||||
"INSERT INTO contact_profiles (display_name, full_name, image, user_id, preferences, created_at, updated_at) VALUES (?,?,?,?,?,?,?)"
|
||||
(displayName, fullName, image, userId, userPreferences, currentTs, currentTs)
|
||||
"INSERT INTO contact_profiles (display_name, full_name, short_descr, image, user_id, preferences, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?)"
|
||||
(displayName, fullName, shortDescr, image, userId, userPreferences, currentTs, currentTs)
|
||||
profileId <- insertedRowId db
|
||||
DB.execute
|
||||
db
|
||||
@@ -156,7 +156,7 @@ createUserRecordAt db (AgentUserId auId) Profile {displayName, fullName, image,
|
||||
(profileId, displayName, userId, BI True, currentTs, currentTs, currentTs)
|
||||
contactId <- insertedRowId db
|
||||
DB.execute db "UPDATE users SET contact_id = ? WHERE user_id = ?" (contactId, userId)
|
||||
pure $ toUser $ (userId, auId, contactId, profileId, BI activeUser, order, displayName, fullName, image, Nothing, userPreferences) :. (BI showNtfs, BI sendRcptsContacts, BI sendRcptsSmallGroups, Nothing, Nothing, Nothing, Nothing)
|
||||
pure $ toUser $ (userId, auId, contactId, profileId, BI activeUser, order, displayName, fullName, shortDescr, image, Nothing, userPreferences) :. (BI showNtfs, BI sendRcptsContacts, BI sendRcptsSmallGroups, Nothing, Nothing, Nothing, Nothing)
|
||||
|
||||
-- TODO [mentions]
|
||||
getUsersInfo :: DB.Connection -> IO [UserInfo]
|
||||
@@ -344,14 +344,14 @@ getUserContactProfiles db User {userId} =
|
||||
<$> DB.query
|
||||
db
|
||||
[sql|
|
||||
SELECT display_name, full_name, image, contact_link, preferences
|
||||
SELECT display_name, full_name, short_descr, image, contact_link, preferences
|
||||
FROM contact_profiles
|
||||
WHERE user_id = ?
|
||||
|]
|
||||
(Only userId)
|
||||
where
|
||||
toContactProfile :: (ContactName, Text, Maybe ImageData, Maybe ConnLinkContact, Maybe Preferences) -> Profile
|
||||
toContactProfile (displayName, fullName, image, contactLink, preferences) = Profile {displayName, fullName, image, contactLink, preferences}
|
||||
toContactProfile :: (ContactName, Text, Maybe Text, Maybe ImageData, Maybe ConnLinkContact, Maybe Preferences) -> Profile
|
||||
toContactProfile (displayName, fullName, shortDescr, image, contactLink, preferences) = Profile {displayName, fullName, shortDescr, image, contactLink, preferences}
|
||||
|
||||
createUserContactLink :: DB.Connection -> User -> ConnId -> CreatedLinkContact -> SubscriptionMode -> ExceptT StoreError IO ()
|
||||
createUserContactLink db User {userId} agentConnId (CCLink cReq shortLink) subMode =
|
||||
|
||||
@@ -134,6 +134,7 @@ import Simplex.Chat.Store.SQLite.Migrations.M20250513_group_scope
|
||||
import Simplex.Chat.Store.SQLite.Migrations.M20250526_short_links
|
||||
import Simplex.Chat.Store.SQLite.Migrations.M20250702_contact_requests_remove_cascade_delete
|
||||
import Simplex.Chat.Store.SQLite.Migrations.M20250704_groups_conn_link_prepared_connection
|
||||
import Simplex.Chat.Store.SQLite.Migrations.M20250709_profile_short_descr
|
||||
import Simplex.Messaging.Agent.Store.Shared (Migration (..))
|
||||
|
||||
schemaMigrations :: [(String, Query, Maybe Query)]
|
||||
@@ -267,7 +268,8 @@ schemaMigrations =
|
||||
("20250513_group_scope", m20250513_group_scope, Just down_m20250513_group_scope),
|
||||
("20250526_short_links", m20250526_short_links, Just down_m20250526_short_links),
|
||||
("20250702_contact_requests_remove_cascade_delete", m20250702_contact_requests_remove_cascade_delete, Just down_m20250702_contact_requests_remove_cascade_delete),
|
||||
("20250704_groups_conn_link_prepared_connection", m20250704_groups_conn_link_prepared_connection, Just down_m20250704_groups_conn_link_prepared_connection)
|
||||
("20250704_groups_conn_link_prepared_connection", m20250704_groups_conn_link_prepared_connection, Just down_m20250704_groups_conn_link_prepared_connection),
|
||||
("20250709_profile_short_descr", m20250709_profile_short_descr, Just down_m20250709_profile_short_descr)
|
||||
]
|
||||
|
||||
-- | The list of migrations in ascending order by date
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
{-# LANGUAGE QuasiQuotes #-}
|
||||
|
||||
module Simplex.Chat.Store.SQLite.Migrations.M20250709_profile_short_descr where
|
||||
|
||||
import Database.SQLite.Simple (Query)
|
||||
import Database.SQLite.Simple.QQ (sql)
|
||||
|
||||
m20250709_profile_short_descr :: Query
|
||||
m20250709_profile_short_descr =
|
||||
[sql|
|
||||
ALTER TABLE contact_profiles ADD COLUMN short_descr TEXT;
|
||||
ALTER TABLE group_profiles ADD COLUMN short_descr TEXT;
|
||||
|]
|
||||
|
||||
down_m20250709_profile_short_descr :: Query
|
||||
down_m20250709_profile_short_descr =
|
||||
[sql|
|
||||
ALTER TABLE contact_profiles DROP COLUMN short_descr;
|
||||
ALTER TABLE group_profiles DROP COLUMN short_descr;
|
||||
|]
|
||||
@@ -60,7 +60,7 @@ Plan:
|
||||
Query:
|
||||
SELECT
|
||||
-- GroupInfo
|
||||
g.group_id, g.local_display_name, gp.display_name, gp.full_name, g.local_alias, gp.description, gp.image,
|
||||
g.group_id, g.local_display_name, gp.display_name, gp.full_name, gp.short_descr, g.local_alias, gp.description, gp.image,
|
||||
g.enable_ntfs, g.send_rcpts, g.favorite, gp.preferences, gp.member_admission,
|
||||
g.created_at, g.updated_at, g.chat_ts, g.user_member_profile_sent_at,
|
||||
g.conn_full_link_to_connect, g.conn_short_link_to_connect, g.conn_link_prepared_connection, g.conn_link_started_connection, g.welcome_shared_msg_id, g.request_shared_msg_id,
|
||||
@@ -70,12 +70,12 @@ Query:
|
||||
mu.group_member_id, mu.group_id, mu.member_id, mu.peer_chat_min_version, mu.peer_chat_max_version, mu.member_role, mu.member_category,
|
||||
mu.member_status, mu.show_messages, mu.member_restriction, mu.invited_by, mu.invited_by_group_member_id, mu.local_display_name, mu.contact_id, mu.contact_profile_id, pu.contact_profile_id,
|
||||
-- GroupInfo {membership = GroupMember {memberProfile}}
|
||||
pu.display_name, pu.full_name, pu.image, pu.contact_link, pu.local_alias, pu.preferences,
|
||||
pu.display_name, pu.full_name, pu.short_descr, pu.image, pu.contact_link, pu.local_alias, pu.preferences,
|
||||
mu.created_at, mu.updated_at,
|
||||
mu.support_chat_ts, mu.support_chat_items_unread, mu.support_chat_items_member_attention, mu.support_chat_items_mentions, mu.support_chat_last_msg_from_member_ts,
|
||||
-- from GroupMember
|
||||
m.group_member_id, m.group_id, m.member_id, m.peer_chat_min_version, m.peer_chat_max_version, m.member_role, m.member_category, m.member_status, m.show_messages, m.member_restriction,
|
||||
m.invited_by, m.invited_by_group_member_id, m.local_display_name, m.contact_id, m.contact_profile_id, p.contact_profile_id, p.display_name, p.full_name, p.image, p.contact_link, p.local_alias, p.preferences,
|
||||
m.invited_by, m.invited_by_group_member_id, m.local_display_name, m.contact_id, m.contact_profile_id, p.contact_profile_id, p.display_name, p.full_name, p.short_descr, p.image, p.contact_link, p.local_alias, p.preferences,
|
||||
m.created_at, m.updated_at,
|
||||
m.support_chat_ts, m.support_chat_items_unread, m.support_chat_items_member_attention, m.support_chat_items_mentions, m.support_chat_last_msg_from_member_ts
|
||||
FROM group_members m
|
||||
@@ -196,7 +196,7 @@ Plan:
|
||||
Query:
|
||||
SELECT
|
||||
-- Contact
|
||||
ct.contact_id, ct.contact_profile_id, ct.local_display_name, ct.via_group, cp.display_name, cp.full_name, cp.image, cp.contact_link, cp.local_alias, ct.contact_used, ct.contact_status, ct.enable_ntfs, ct.send_rcpts, ct.favorite,
|
||||
ct.contact_id, ct.contact_profile_id, ct.local_display_name, ct.via_group, cp.display_name, cp.full_name, cp.short_descr, cp.image, cp.contact_link, cp.local_alias, ct.contact_used, ct.contact_status, ct.enable_ntfs, ct.send_rcpts, ct.favorite,
|
||||
cp.preferences, ct.user_preferences, ct.created_at, ct.updated_at, ct.chat_ts, ct.conn_full_link_to_connect, ct.conn_short_link_to_connect, ct.welcome_shared_msg_id, ct.request_shared_msg_id, ct.contact_request_id,
|
||||
ct.contact_group_member_id, ct.contact_grp_inv_sent, ct.ui_themes, ct.chat_deleted, ct.custom_data, ct.chat_item_ttl,
|
||||
-- Connection
|
||||
@@ -287,6 +287,7 @@ Query:
|
||||
UPDATE contact_profiles
|
||||
SET display_name = ?,
|
||||
full_name = ?,
|
||||
short_descr = ?,
|
||||
image = ?,
|
||||
contact_link = ?,
|
||||
updated_at = ?
|
||||
@@ -383,7 +384,7 @@ Plan:
|
||||
|
||||
Query:
|
||||
SELECT
|
||||
c.contact_profile_id, c.local_display_name, c.via_group, p.display_name, p.full_name, p.image, p.contact_link, p.local_alias, c.contact_used, c.contact_status, c.enable_ntfs, c.send_rcpts, c.favorite,
|
||||
c.contact_profile_id, c.local_display_name, c.via_group, p.display_name, p.full_name, p.short_descr, p.image, p.contact_link, p.local_alias, c.contact_used, c.contact_status, c.enable_ntfs, c.send_rcpts, c.favorite,
|
||||
p.preferences, c.user_preferences, c.created_at, c.updated_at, c.chat_ts, c.conn_full_link_to_connect, c.conn_short_link_to_connect, c.welcome_shared_msg_id, c.request_shared_msg_id, c.contact_request_id,
|
||||
c.contact_group_member_id, c.contact_grp_inv_sent, c.ui_themes, c.chat_deleted, c.custom_data, c.chat_item_ttl
|
||||
FROM contacts c
|
||||
@@ -398,7 +399,7 @@ Query:
|
||||
SELECT
|
||||
cr.contact_request_id, cr.local_display_name, cr.agent_invitation_id,
|
||||
cr.contact_id, cr.business_group_id, cr.user_contact_link_id,
|
||||
cr.contact_profile_id, p.display_name, p.full_name, p.image, p.contact_link, cr.xcontact_id,
|
||||
cr.contact_profile_id, p.display_name, p.full_name, p.short_descr, p.image, p.contact_link, cr.xcontact_id,
|
||||
cr.pq_support, cr.welcome_shared_msg_id, cr.request_shared_msg_id, p.preferences,
|
||||
cr.created_at, cr.updated_at,
|
||||
cr.peer_chat_min_version, cr.peer_chat_max_version
|
||||
@@ -644,7 +645,7 @@ SEARCH m USING INTEGER PRIMARY KEY (rowid=?)
|
||||
SEARCH ct USING INTEGER PRIMARY KEY (rowid=?)
|
||||
|
||||
Query:
|
||||
SELECT gp.display_name, gp.full_name, gp.description, gp.image, gp.preferences, gp.member_admission
|
||||
SELECT gp.display_name, gp.full_name, gp.short_descr, gp.description, gp.image, gp.preferences, gp.member_admission
|
||||
FROM group_profiles gp
|
||||
JOIN groups g ON gp.group_profile_id = g.group_profile_id
|
||||
WHERE g.group_id = ?
|
||||
@@ -673,7 +674,7 @@ Query:
|
||||
-- GroupMember
|
||||
m.group_member_id, m.group_id, m.member_id, m.peer_chat_min_version, m.peer_chat_max_version, m.member_role, m.member_category,
|
||||
m.member_status, m.show_messages, m.member_restriction, m.invited_by, m.invited_by_group_member_id, m.local_display_name, m.contact_id, m.contact_profile_id, p.contact_profile_id,
|
||||
p.display_name, p.full_name, p.image, p.contact_link, p.local_alias, p.preferences,
|
||||
p.display_name, p.full_name, p.short_descr, p.image, p.contact_link, p.local_alias, p.preferences,
|
||||
m.created_at, m.updated_at,
|
||||
m.support_chat_ts, m.support_chat_items_unread, m.support_chat_items_member_attention, m.support_chat_items_mentions, m.support_chat_last_msg_from_member_ts
|
||||
FROM group_members m
|
||||
@@ -867,7 +868,7 @@ Query:
|
||||
-- GroupMember
|
||||
m.group_member_id, m.group_id, m.member_id, m.peer_chat_min_version, m.peer_chat_max_version, m.member_role, m.member_category,
|
||||
m.member_status, m.show_messages, m.member_restriction, m.invited_by, m.invited_by_group_member_id, m.local_display_name, m.contact_id, m.contact_profile_id, p.contact_profile_id,
|
||||
p.display_name, p.full_name, p.image, p.contact_link, p.local_alias, p.preferences,
|
||||
p.display_name, p.full_name, p.short_descr, p.image, p.contact_link, p.local_alias, p.preferences,
|
||||
m.created_at, m.updated_at,
|
||||
m.support_chat_ts, m.support_chat_items_unread, m.support_chat_items_member_attention, m.support_chat_items_mentions, m.support_chat_last_msg_from_member_ts,
|
||||
-- quoted ChatItem
|
||||
@@ -875,13 +876,13 @@ Query:
|
||||
-- quoted GroupMember
|
||||
rm.group_member_id, rm.group_id, rm.member_id, rm.peer_chat_min_version, rm.peer_chat_max_version, rm.member_role, rm.member_category,
|
||||
rm.member_status, rm.show_messages, rm.member_restriction, rm.invited_by, rm.invited_by_group_member_id, rm.local_display_name, rm.contact_id, rm.contact_profile_id, rp.contact_profile_id,
|
||||
rp.display_name, rp.full_name, rp.image, rp.contact_link, rp.local_alias, rp.preferences,
|
||||
rp.display_name, rp.full_name, rp.short_descr, rp.image, rp.contact_link, rp.local_alias, rp.preferences,
|
||||
rm.created_at, rm.updated_at,
|
||||
rm.support_chat_ts, rm.support_chat_items_unread, rm.support_chat_items_member_attention, rm.support_chat_items_mentions, rm.support_chat_last_msg_from_member_ts,
|
||||
-- deleted by GroupMember
|
||||
dbm.group_member_id, dbm.group_id, dbm.member_id, dbm.peer_chat_min_version, dbm.peer_chat_max_version, dbm.member_role, dbm.member_category,
|
||||
dbm.member_status, dbm.show_messages, dbm.member_restriction, dbm.invited_by, dbm.invited_by_group_member_id, dbm.local_display_name, dbm.contact_id, dbm.contact_profile_id, dbp.contact_profile_id,
|
||||
dbp.display_name, dbp.full_name, dbp.image, dbp.contact_link, dbp.local_alias, dbp.preferences,
|
||||
dbp.display_name, dbp.full_name, dbp.short_descr, dbp.image, dbp.contact_link, dbp.local_alias, dbp.preferences,
|
||||
dbm.created_at, dbm.updated_at,
|
||||
dbm.support_chat_ts, dbm.support_chat_items_unread, dbm.support_chat_items_member_attention, dbm.support_chat_items_mentions, dbm.support_chat_last_msg_from_member_ts
|
||||
FROM chat_items i
|
||||
@@ -933,7 +934,7 @@ SEARCH ri USING COVERING INDEX idx_chat_items_direct_shared_msg_id (user_id=? AN
|
||||
Query:
|
||||
SELECT
|
||||
-- Contact
|
||||
ct.contact_id, ct.contact_profile_id, ct.local_display_name, ct.via_group, cp.display_name, cp.full_name, cp.image, cp.contact_link, cp.local_alias, ct.contact_used, ct.contact_status, ct.enable_ntfs, ct.send_rcpts, ct.favorite,
|
||||
ct.contact_id, ct.contact_profile_id, ct.local_display_name, ct.via_group, cp.display_name, cp.full_name, cp.short_descr, cp.image, cp.contact_link, cp.local_alias, ct.contact_used, ct.contact_status, ct.enable_ntfs, ct.send_rcpts, ct.favorite,
|
||||
cp.preferences, ct.user_preferences, ct.created_at, ct.updated_at, ct.chat_ts, ct.conn_full_link_to_connect, ct.conn_short_link_to_connect, ct.welcome_shared_msg_id, ct.request_shared_msg_id, ct.contact_request_id,
|
||||
ct.contact_group_member_id, ct.contact_grp_inv_sent, ct.ui_themes, ct.chat_deleted, ct.custom_data, ct.chat_item_ttl,
|
||||
-- Connection
|
||||
@@ -963,7 +964,7 @@ USE TEMP B-TREE FOR ORDER BY
|
||||
Query:
|
||||
SELECT
|
||||
-- GroupInfo
|
||||
g.group_id, g.local_display_name, gp.display_name, gp.full_name, g.local_alias, gp.description, gp.image,
|
||||
g.group_id, g.local_display_name, gp.display_name, gp.full_name, gp.short_descr, g.local_alias, gp.description, gp.image,
|
||||
g.enable_ntfs, g.send_rcpts, g.favorite, gp.preferences, gp.member_admission,
|
||||
g.created_at, g.updated_at, g.chat_ts, g.user_member_profile_sent_at,
|
||||
g.conn_full_link_to_connect, g.conn_short_link_to_connect, g.conn_link_prepared_connection, g.conn_link_started_connection, g.welcome_shared_msg_id, g.request_shared_msg_id,
|
||||
@@ -973,12 +974,12 @@ Query:
|
||||
mu.group_member_id, mu.group_id, mu.member_id, mu.peer_chat_min_version, mu.peer_chat_max_version, mu.member_role, mu.member_category,
|
||||
mu.member_status, mu.show_messages, mu.member_restriction, mu.invited_by, mu.invited_by_group_member_id, mu.local_display_name, mu.contact_id, mu.contact_profile_id, pu.contact_profile_id,
|
||||
-- GroupInfo {membership = GroupMember {memberProfile}}
|
||||
pu.display_name, pu.full_name, pu.image, pu.contact_link, pu.local_alias, pu.preferences,
|
||||
pu.display_name, pu.full_name, pu.short_descr, pu.image, pu.contact_link, pu.local_alias, pu.preferences,
|
||||
mu.created_at, mu.updated_at,
|
||||
mu.support_chat_ts, mu.support_chat_items_unread, mu.support_chat_items_member_attention, mu.support_chat_items_mentions, mu.support_chat_last_msg_from_member_ts,
|
||||
-- via GroupMember
|
||||
m.group_member_id, m.group_id, m.member_id, m.peer_chat_min_version, m.peer_chat_max_version, m.member_role, m.member_category, m.member_status, m.show_messages, m.member_restriction,
|
||||
m.invited_by, m.invited_by_group_member_id, m.local_display_name, m.contact_id, m.contact_profile_id, p.contact_profile_id, p.display_name, p.full_name, p.image, p.contact_link, p.local_alias, p.preferences,
|
||||
m.invited_by, m.invited_by_group_member_id, m.local_display_name, m.contact_id, m.contact_profile_id, p.contact_profile_id, p.display_name, p.full_name, p.short_descr, p.image, p.contact_link, p.local_alias, p.preferences,
|
||||
m.created_at, m.updated_at,
|
||||
m.support_chat_ts, m.support_chat_items_unread, m.support_chat_items_member_attention, m.support_chat_items_mentions, m.support_chat_last_msg_from_member_ts,
|
||||
c.connection_id, c.agent_conn_id, c.conn_level, c.via_contact, c.via_user_contact_link, c.via_group_link, c.group_link_id, c.xcontact_id, c.custom_user_profile_id,
|
||||
@@ -1013,14 +1014,14 @@ SEARCH cc USING COVERING INDEX idx_connections_group_member (user_id=? AND group
|
||||
|
||||
Query:
|
||||
SELECT
|
||||
g.group_id, g.local_display_name, gp.display_name, gp.full_name, g.local_alias, gp.description, gp.image,
|
||||
g.group_id, g.local_display_name, gp.display_name, gp.full_name, gp.short_descr, g.local_alias, gp.description, gp.image,
|
||||
g.enable_ntfs, g.send_rcpts, g.favorite, gp.preferences, gp.member_admission,
|
||||
g.created_at, g.updated_at, g.chat_ts, g.user_member_profile_sent_at,
|
||||
g.conn_full_link_to_connect, g.conn_short_link_to_connect, g.conn_link_prepared_connection, g.conn_link_started_connection, g.welcome_shared_msg_id, g.request_shared_msg_id,
|
||||
g.business_chat, g.business_member_id, g.customer_member_id,
|
||||
g.ui_themes, g.custom_data, g.chat_item_ttl, g.members_require_attention,
|
||||
mu.group_member_id, g.group_id, mu.member_id, mu.peer_chat_min_version, mu.peer_chat_max_version, mu.member_role, mu.member_category, mu.member_status, mu.show_messages, mu.member_restriction,
|
||||
mu.invited_by, mu.invited_by_group_member_id, mu.local_display_name, mu.contact_id, mu.contact_profile_id, pu.contact_profile_id, pu.display_name, pu.full_name, pu.image, pu.contact_link, pu.local_alias, pu.preferences,
|
||||
mu.invited_by, mu.invited_by_group_member_id, mu.local_display_name, mu.contact_id, mu.contact_profile_id, pu.contact_profile_id, pu.display_name, pu.full_name, pu.short_descr, pu.image, pu.contact_link, pu.local_alias, pu.preferences,
|
||||
mu.created_at, mu.updated_at,
|
||||
mu.support_chat_ts, mu.support_chat_items_unread, mu.support_chat_items_member_attention, mu.support_chat_items_mentions, mu.support_chat_last_msg_from_member_ts
|
||||
FROM groups g
|
||||
@@ -1028,9 +1029,10 @@ Query:
|
||||
JOIN group_members mu USING (group_id)
|
||||
JOIN contact_profiles pu ON pu.contact_profile_id = COALESCE(mu.member_profile_id, mu.contact_profile_id)
|
||||
WHERE g.user_id = ? AND mu.contact_id = ?
|
||||
AND (LOWER(gp.display_name) LIKE '%' || LOWER(?) || '%'
|
||||
OR LOWER(gp.full_name) LIKE '%' || LOWER(?) || '%'
|
||||
OR LOWER(gp.description) LIKE '%' || LOWER(?) || '%'
|
||||
AND (LOWER(gp.display_name) LIKE '%' || ? || '%'
|
||||
OR LOWER(gp.full_name) LIKE '%' || ? || '%'
|
||||
OR LOWER(gp.short_descr) LIKE '%' || ? || '%'
|
||||
OR LOWER(gp.description) LIKE '%' || ? || '%'
|
||||
)
|
||||
|
||||
Plan:
|
||||
@@ -1444,7 +1446,7 @@ SEARCH group_members USING INTEGER PRIMARY KEY (rowid=?)
|
||||
|
||||
Query:
|
||||
UPDATE group_profiles
|
||||
SET display_name = ?, full_name = ?, description = ?, image = ?, preferences = ?, member_admission = ?, updated_at = ?
|
||||
SET display_name = ?, full_name = ?, short_descr = ?, description = ?, image = ?, preferences = ?, member_admission = ?, updated_at = ?
|
||||
WHERE group_profile_id IN (
|
||||
SELECT group_profile_id
|
||||
FROM groups
|
||||
@@ -1524,7 +1526,7 @@ Plan:
|
||||
Query:
|
||||
SELECT
|
||||
-- Contact
|
||||
ct.contact_id, ct.contact_profile_id, ct.local_display_name, ct.via_group, cp.display_name, cp.full_name, cp.image, cp.contact_link, cp.local_alias, ct.contact_used, ct.contact_status, ct.enable_ntfs, ct.send_rcpts, ct.favorite,
|
||||
ct.contact_id, ct.contact_profile_id, ct.local_display_name, ct.via_group, cp.display_name, cp.full_name, cp.short_descr, cp.image, cp.contact_link, cp.local_alias, ct.contact_used, ct.contact_status, ct.enable_ntfs, ct.send_rcpts, ct.favorite,
|
||||
cp.preferences, ct.user_preferences, ct.created_at, ct.updated_at, ct.chat_ts, ct.conn_full_link_to_connect, ct.conn_short_link_to_connect, ct.welcome_shared_msg_id, ct.request_shared_msg_id, ct.contact_request_id,
|
||||
ct.contact_group_member_id, ct.contact_grp_inv_sent, ct.ui_themes, ct.chat_deleted, ct.custom_data, ct.chat_item_ttl,
|
||||
-- Connection
|
||||
@@ -1627,7 +1629,7 @@ Query:
|
||||
SELECT
|
||||
cr.contact_request_id, cr.local_display_name, cr.agent_invitation_id,
|
||||
cr.contact_id, cr.business_group_id, cr.user_contact_link_id,
|
||||
cr.contact_profile_id, p.display_name, p.full_name, p.image, p.contact_link, cr.xcontact_id,
|
||||
cr.contact_profile_id, p.display_name, p.full_name, p.short_descr, p.image, p.contact_link, cr.xcontact_id,
|
||||
cr.pq_support, cr.welcome_shared_msg_id, cr.request_shared_msg_id, p.preferences,
|
||||
cr.created_at, cr.updated_at,
|
||||
cr.peer_chat_min_version, cr.peer_chat_max_version
|
||||
@@ -1641,9 +1643,10 @@ Query:
|
||||
AND cr.contact_id IS NULL
|
||||
AND cr.business_group_id IS NULL
|
||||
AND (
|
||||
LOWER(cr.local_display_name) LIKE '%' || LOWER(?) || '%'
|
||||
OR LOWER(p.display_name) LIKE '%' || LOWER(?) || '%'
|
||||
OR LOWER(p.full_name) LIKE '%' || LOWER(?) || '%'
|
||||
LOWER(cr.local_display_name) LIKE '%' || ? || '%'
|
||||
OR LOWER(p.display_name) LIKE '%' || ? || '%'
|
||||
OR LOWER(p.full_name) LIKE '%' || ? || '%'
|
||||
OR LOWER(p.short_descr) LIKE '%' || ? || '%'
|
||||
)
|
||||
AND cr.updated_at < ? ORDER BY cr.updated_at DESC LIMIT ?
|
||||
Plan:
|
||||
@@ -1655,7 +1658,7 @@ Query:
|
||||
SELECT
|
||||
cr.contact_request_id, cr.local_display_name, cr.agent_invitation_id,
|
||||
cr.contact_id, cr.business_group_id, cr.user_contact_link_id,
|
||||
cr.contact_profile_id, p.display_name, p.full_name, p.image, p.contact_link, cr.xcontact_id,
|
||||
cr.contact_profile_id, p.display_name, p.full_name, p.short_descr, p.image, p.contact_link, cr.xcontact_id,
|
||||
cr.pq_support, cr.welcome_shared_msg_id, cr.request_shared_msg_id, p.preferences,
|
||||
cr.created_at, cr.updated_at,
|
||||
cr.peer_chat_min_version, cr.peer_chat_max_version
|
||||
@@ -1669,9 +1672,10 @@ Query:
|
||||
AND cr.contact_id IS NULL
|
||||
AND cr.business_group_id IS NULL
|
||||
AND (
|
||||
LOWER(cr.local_display_name) LIKE '%' || LOWER(?) || '%'
|
||||
OR LOWER(p.display_name) LIKE '%' || LOWER(?) || '%'
|
||||
OR LOWER(p.full_name) LIKE '%' || LOWER(?) || '%'
|
||||
LOWER(cr.local_display_name) LIKE '%' || ? || '%'
|
||||
OR LOWER(p.display_name) LIKE '%' || ? || '%'
|
||||
OR LOWER(p.full_name) LIKE '%' || ? || '%'
|
||||
OR LOWER(p.short_descr) LIKE '%' || ? || '%'
|
||||
)
|
||||
AND cr.updated_at > ? ORDER BY cr.updated_at ASC LIMIT ?
|
||||
Plan:
|
||||
@@ -1683,7 +1687,7 @@ Query:
|
||||
SELECT
|
||||
cr.contact_request_id, cr.local_display_name, cr.agent_invitation_id,
|
||||
cr.contact_id, cr.business_group_id, cr.user_contact_link_id,
|
||||
cr.contact_profile_id, p.display_name, p.full_name, p.image, p.contact_link, cr.xcontact_id,
|
||||
cr.contact_profile_id, p.display_name, p.full_name, p.short_descr, p.image, p.contact_link, cr.xcontact_id,
|
||||
cr.pq_support, cr.welcome_shared_msg_id, cr.request_shared_msg_id, p.preferences,
|
||||
cr.created_at, cr.updated_at,
|
||||
cr.peer_chat_min_version, cr.peer_chat_max_version
|
||||
@@ -1697,9 +1701,10 @@ Query:
|
||||
AND cr.contact_id IS NULL
|
||||
AND cr.business_group_id IS NULL
|
||||
AND (
|
||||
LOWER(cr.local_display_name) LIKE '%' || LOWER(?) || '%'
|
||||
OR LOWER(p.display_name) LIKE '%' || LOWER(?) || '%'
|
||||
OR LOWER(p.full_name) LIKE '%' || LOWER(?) || '%'
|
||||
LOWER(cr.local_display_name) LIKE '%' || ? || '%'
|
||||
OR LOWER(p.display_name) LIKE '%' || ? || '%'
|
||||
OR LOWER(p.full_name) LIKE '%' || ? || '%'
|
||||
OR LOWER(p.short_descr) LIKE '%' || ? || '%'
|
||||
)
|
||||
ORDER BY cr.updated_at DESC LIMIT ?
|
||||
Plan:
|
||||
@@ -1742,10 +1747,11 @@ Query:
|
||||
JOIN contact_profiles cp ON ct.contact_profile_id = cp.contact_profile_id
|
||||
WHERE ct.user_id = ? AND ct.is_user = 0 AND ct.deleted = 0 AND ct.contact_used = 1
|
||||
AND (
|
||||
LOWER(ct.local_display_name) LIKE '%' || LOWER(?) || '%'
|
||||
OR LOWER(cp.display_name) LIKE '%' || LOWER(?) || '%'
|
||||
OR LOWER(cp.full_name) LIKE '%' || LOWER(?) || '%'
|
||||
OR LOWER(cp.local_alias) LIKE '%' || LOWER(?) || '%'
|
||||
LOWER(ct.local_display_name) LIKE '%' || ? || '%'
|
||||
OR LOWER(cp.display_name) LIKE '%' || ? || '%'
|
||||
OR LOWER(cp.full_name) LIKE '%' || ? || '%'
|
||||
OR LOWER(cp.short_descr) LIKE '%' || ? || '%'
|
||||
OR LOWER(cp.local_alias) LIKE '%' || ? || '%'
|
||||
)
|
||||
ORDER BY ct.chat_ts DESC LIMIT ?
|
||||
Plan:
|
||||
@@ -2113,10 +2119,11 @@ Query:
|
||||
JOIN group_profiles gp ON gp.group_profile_id = g.group_profile_id
|
||||
WHERE g.user_id = ?
|
||||
AND (
|
||||
LOWER(g.local_display_name) LIKE '%' || LOWER(?) || '%'
|
||||
OR LOWER(gp.display_name) LIKE '%' || LOWER(?) || '%'
|
||||
OR LOWER(gp.full_name) LIKE '%' || LOWER(?) || '%'
|
||||
OR LOWER(gp.description) LIKE '%' || LOWER(?) || '%'
|
||||
LOWER(g.local_display_name) LIKE '%' || ? || '%'
|
||||
OR LOWER(gp.display_name) LIKE '%' || ? || '%'
|
||||
OR LOWER(gp.full_name) LIKE '%' || ? || '%'
|
||||
OR LOWER(gp.short_descr) LIKE '%' || ? || '%'
|
||||
OR LOWER(gp.description) LIKE '%' || ? || '%'
|
||||
)
|
||||
ORDER BY g.chat_ts DESC LIMIT ?
|
||||
Plan:
|
||||
@@ -3169,7 +3176,7 @@ Plan:
|
||||
SEARCH connections USING INTEGER PRIMARY KEY (rowid=?)
|
||||
|
||||
Query:
|
||||
SELECT cp.display_name, cp.full_name, cp.image, cp.contact_link, cp.local_alias, cp.preferences -- , ct.user_preferences
|
||||
SELECT cp.contact_profile_id, cp.display_name, cp.full_name, cp.short_descr, cp.image, cp.contact_link, cp.local_alias, cp.preferences -- , ct.user_preferences
|
||||
FROM contact_profiles cp
|
||||
WHERE cp.user_id = ? AND cp.contact_profile_id = ?
|
||||
|
||||
@@ -3183,19 +3190,8 @@ Query:
|
||||
WHERE ct.user_id = ?
|
||||
AND ct.contact_status = ? AND ct.deleted = 0 AND ct.is_user = 0
|
||||
AND p.display_name = ? AND p.full_name = ?
|
||||
AND p.image = ?
|
||||
Plan:
|
||||
SEARCH ct USING INDEX idx_contacts_chat_ts (user_id=?)
|
||||
SEARCH p USING INTEGER PRIMARY KEY (rowid=?)
|
||||
|
||||
Query:
|
||||
SELECT ct.contact_id
|
||||
FROM contacts ct
|
||||
JOIN contact_profiles p ON ct.contact_profile_id = p.contact_profile_id
|
||||
WHERE ct.user_id = ?
|
||||
AND ct.contact_status = ? AND ct.deleted = 0 AND ct.is_user = 0
|
||||
AND p.display_name = ? AND p.full_name = ?
|
||||
AND p.image is NULL
|
||||
AND p.short_descr IS ? AND p.image IS ?
|
||||
|
||||
Plan:
|
||||
SEARCH ct USING INDEX idx_contacts_chat_ts (user_id=?)
|
||||
SEARCH p USING INTEGER PRIMARY KEY (rowid=?)
|
||||
@@ -3223,7 +3219,7 @@ SEARCH f USING PRIMARY KEY (file_id=?)
|
||||
SEARCH d USING INTEGER PRIMARY KEY (rowid=?)
|
||||
|
||||
Query:
|
||||
SELECT display_name, full_name, image, contact_link, preferences
|
||||
SELECT display_name, full_name, short_descr, image, contact_link, preferences
|
||||
FROM contact_profiles
|
||||
WHERE user_id = ?
|
||||
|
||||
@@ -3324,19 +3320,8 @@ Query:
|
||||
WHERE m.user_id = ? AND m.contact_id IS NULL
|
||||
AND m.member_category != ?
|
||||
AND p.display_name = ? AND p.full_name = ?
|
||||
AND p.image = ?
|
||||
Plan:
|
||||
SEARCH m USING INDEX idx_group_members_user_id (user_id=?)
|
||||
SEARCH p USING INTEGER PRIMARY KEY (rowid=?)
|
||||
|
||||
Query:
|
||||
SELECT m.group_member_id
|
||||
FROM group_members m
|
||||
JOIN contact_profiles p ON p.contact_profile_id = COALESCE(m.member_profile_id, m.contact_profile_id)
|
||||
WHERE m.user_id = ? AND m.contact_id IS NULL
|
||||
AND m.member_category != ?
|
||||
AND p.display_name = ? AND p.full_name = ?
|
||||
AND p.image is NULL
|
||||
AND p.short_descr IS ? AND p.image IS ?
|
||||
|
||||
Plan:
|
||||
SEARCH m USING INDEX idx_group_members_user_id (user_id=?)
|
||||
SEARCH p USING INTEGER PRIMARY KEY (rowid=?)
|
||||
@@ -4133,8 +4118,8 @@ Query:
|
||||
Plan:
|
||||
|
||||
Query:
|
||||
INSERT INTO contact_profiles (display_name, full_name, image, user_id, incognito, created_at, updated_at)
|
||||
VALUES (?,?,?,?,?,?,?)
|
||||
INSERT INTO contact_profiles (display_name, full_name, short_descr, image, user_id, incognito, created_at, updated_at)
|
||||
VALUES (?,?,?,?,?,?,?,?)
|
||||
|
||||
Plan:
|
||||
SEARCH contact_requests USING COVERING INDEX idx_contact_requests_contact_profile_id (contact_profile_id=?)
|
||||
@@ -4389,7 +4374,7 @@ SEARCH contact_profiles USING INTEGER PRIMARY KEY (rowid=?)
|
||||
|
||||
Query:
|
||||
UPDATE contact_profiles
|
||||
SET display_name = ?, full_name = ?, image = ?, contact_link = ?, preferences = ?, updated_at = ?
|
||||
SET display_name = ?, full_name = ?, short_descr = ?, image = ?, contact_link = ?, preferences = ?, updated_at = ?
|
||||
WHERE user_id = ? AND contact_profile_id = ?
|
||||
|
||||
Plan:
|
||||
@@ -4397,7 +4382,7 @@ SEARCH contact_profiles USING INTEGER PRIMARY KEY (rowid=?)
|
||||
|
||||
Query:
|
||||
UPDATE contact_profiles
|
||||
SET display_name = ?, full_name = ?, image = ?, contact_link = NULL, preferences = NULL, updated_at = ?
|
||||
SET display_name = ?, full_name = ?, short_descr = ?, image = ?, contact_link = NULL, preferences = NULL, updated_at = ?
|
||||
WHERE user_id = ? AND contact_profile_id = ?
|
||||
|
||||
Plan:
|
||||
@@ -4405,7 +4390,7 @@ SEARCH contact_profiles USING INTEGER PRIMARY KEY (rowid=?)
|
||||
|
||||
Query:
|
||||
UPDATE contact_profiles
|
||||
SET display_name = ?, full_name = ?, image = ?, updated_at = ?
|
||||
SET display_name = ?, full_name = ?, short_descr = ?, image = ?, updated_at = ?
|
||||
WHERE user_id = ? AND contact_profile_id = ?
|
||||
|
||||
Plan:
|
||||
@@ -4679,7 +4664,7 @@ SEARCH pending_group_messages USING COVERING INDEX idx_pending_group_messages_me
|
||||
Query:
|
||||
SELECT
|
||||
-- GroupInfo
|
||||
g.group_id, g.local_display_name, gp.display_name, gp.full_name, g.local_alias, gp.description, gp.image,
|
||||
g.group_id, g.local_display_name, gp.display_name, gp.full_name, gp.short_descr, g.local_alias, gp.description, gp.image,
|
||||
g.enable_ntfs, g.send_rcpts, g.favorite, gp.preferences, gp.member_admission,
|
||||
g.created_at, g.updated_at, g.chat_ts, g.user_member_profile_sent_at,
|
||||
g.conn_full_link_to_connect, g.conn_short_link_to_connect, g.conn_link_prepared_connection, g.conn_link_started_connection, g.welcome_shared_msg_id, g.request_shared_msg_id,
|
||||
@@ -4688,7 +4673,7 @@ Query:
|
||||
-- GroupMember - membership
|
||||
mu.group_member_id, mu.group_id, mu.member_id, mu.peer_chat_min_version, mu.peer_chat_max_version, mu.member_role, mu.member_category,
|
||||
mu.member_status, mu.show_messages, mu.member_restriction, mu.invited_by, mu.invited_by_group_member_id, mu.local_display_name, mu.contact_id, mu.contact_profile_id, pu.contact_profile_id,
|
||||
pu.display_name, pu.full_name, pu.image, pu.contact_link, pu.local_alias, pu.preferences,
|
||||
pu.display_name, pu.full_name, pu.short_descr, pu.image, pu.contact_link, pu.local_alias, pu.preferences,
|
||||
mu.created_at, mu.updated_at,
|
||||
mu.support_chat_ts, mu.support_chat_items_unread, mu.support_chat_items_member_attention, mu.support_chat_items_mentions, mu.support_chat_last_msg_from_member_ts
|
||||
FROM groups g
|
||||
@@ -4705,7 +4690,7 @@ SEARCH pu USING INTEGER PRIMARY KEY (rowid=?)
|
||||
Query:
|
||||
SELECT
|
||||
-- GroupInfo
|
||||
g.group_id, g.local_display_name, gp.display_name, gp.full_name, g.local_alias, gp.description, gp.image,
|
||||
g.group_id, g.local_display_name, gp.display_name, gp.full_name, gp.short_descr, g.local_alias, gp.description, gp.image,
|
||||
g.enable_ntfs, g.send_rcpts, g.favorite, gp.preferences, gp.member_admission,
|
||||
g.created_at, g.updated_at, g.chat_ts, g.user_member_profile_sent_at,
|
||||
g.conn_full_link_to_connect, g.conn_short_link_to_connect, g.conn_link_prepared_connection, g.conn_link_started_connection, g.welcome_shared_msg_id, g.request_shared_msg_id,
|
||||
@@ -4714,7 +4699,7 @@ Query:
|
||||
-- GroupMember - membership
|
||||
mu.group_member_id, mu.group_id, mu.member_id, mu.peer_chat_min_version, mu.peer_chat_max_version, mu.member_role, mu.member_category,
|
||||
mu.member_status, mu.show_messages, mu.member_restriction, mu.invited_by, mu.invited_by_group_member_id, mu.local_display_name, mu.contact_id, mu.contact_profile_id, pu.contact_profile_id,
|
||||
pu.display_name, pu.full_name, pu.image, pu.contact_link, pu.local_alias, pu.preferences,
|
||||
pu.display_name, pu.full_name, pu.short_descr, pu.image, pu.contact_link, pu.local_alias, pu.preferences,
|
||||
mu.created_at, mu.updated_at,
|
||||
mu.support_chat_ts, mu.support_chat_items_unread, mu.support_chat_items_member_attention, mu.support_chat_items_mentions, mu.support_chat_last_msg_from_member_ts
|
||||
FROM groups g
|
||||
@@ -4732,7 +4717,7 @@ Query:
|
||||
SELECT
|
||||
cr.contact_request_id, cr.local_display_name, cr.agent_invitation_id,
|
||||
cr.contact_id, cr.business_group_id, cr.user_contact_link_id,
|
||||
cr.contact_profile_id, p.display_name, p.full_name, p.image, p.contact_link, cr.xcontact_id,
|
||||
cr.contact_profile_id, p.display_name, p.full_name, p.short_descr, p.image, p.contact_link, cr.xcontact_id,
|
||||
cr.pq_support, cr.welcome_shared_msg_id, cr.request_shared_msg_id, p.preferences,
|
||||
cr.created_at, cr.updated_at,
|
||||
cr.peer_chat_min_version, cr.peer_chat_max_version
|
||||
@@ -4747,7 +4732,7 @@ Query:
|
||||
SELECT
|
||||
cr.contact_request_id, cr.local_display_name, cr.agent_invitation_id,
|
||||
cr.contact_id, cr.business_group_id, cr.user_contact_link_id,
|
||||
cr.contact_profile_id, p.display_name, p.full_name, p.image, p.contact_link, cr.xcontact_id,
|
||||
cr.contact_profile_id, p.display_name, p.full_name, p.short_descr, p.image, p.contact_link, cr.xcontact_id,
|
||||
cr.pq_support, cr.welcome_shared_msg_id, cr.request_shared_msg_id, p.preferences,
|
||||
cr.created_at, cr.updated_at,
|
||||
cr.peer_chat_min_version, cr.peer_chat_max_version
|
||||
@@ -4761,7 +4746,7 @@ SEARCH p USING INTEGER PRIMARY KEY (rowid=?)
|
||||
Query:
|
||||
SELECT
|
||||
m.group_member_id, m.group_id, m.member_id, m.peer_chat_min_version, m.peer_chat_max_version, m.member_role, m.member_category, m.member_status, m.show_messages, m.member_restriction,
|
||||
m.invited_by, m.invited_by_group_member_id, m.local_display_name, m.contact_id, m.contact_profile_id, p.contact_profile_id, p.display_name, p.full_name, p.image, p.contact_link, p.local_alias, p.preferences,
|
||||
m.invited_by, m.invited_by_group_member_id, m.local_display_name, m.contact_id, m.contact_profile_id, p.contact_profile_id, p.display_name, p.full_name, p.short_descr, p.image, p.contact_link, p.local_alias, p.preferences,
|
||||
m.created_at, m.updated_at,
|
||||
m.support_chat_ts, m.support_chat_items_unread, m.support_chat_items_member_attention, m.support_chat_items_mentions, m.support_chat_last_msg_from_member_ts,
|
||||
c.connection_id, c.agent_conn_id, c.conn_level, c.via_contact, c.via_user_contact_link, c.via_group_link, c.group_link_id, c.xcontact_id, c.custom_user_profile_id,
|
||||
@@ -4794,7 +4779,7 @@ SEARCH cc USING COVERING INDEX idx_connections_group_member (user_id=? AND group
|
||||
Query:
|
||||
SELECT
|
||||
m.group_member_id, m.group_id, m.member_id, m.peer_chat_min_version, m.peer_chat_max_version, m.member_role, m.member_category, m.member_status, m.show_messages, m.member_restriction,
|
||||
m.invited_by, m.invited_by_group_member_id, m.local_display_name, m.contact_id, m.contact_profile_id, p.contact_profile_id, p.display_name, p.full_name, p.image, p.contact_link, p.local_alias, p.preferences,
|
||||
m.invited_by, m.invited_by_group_member_id, m.local_display_name, m.contact_id, m.contact_profile_id, p.contact_profile_id, p.display_name, p.full_name, p.short_descr, p.image, p.contact_link, p.local_alias, p.preferences,
|
||||
m.created_at, m.updated_at,
|
||||
m.support_chat_ts, m.support_chat_items_unread, m.support_chat_items_member_attention, m.support_chat_items_mentions, m.support_chat_last_msg_from_member_ts,
|
||||
c.connection_id, c.agent_conn_id, c.conn_level, c.via_contact, c.via_user_contact_link, c.via_group_link, c.group_link_id, c.xcontact_id, c.custom_user_profile_id,
|
||||
@@ -4819,7 +4804,7 @@ SEARCH cc USING COVERING INDEX idx_connections_group_member (user_id=? AND group
|
||||
Query:
|
||||
SELECT
|
||||
m.group_member_id, m.group_id, m.member_id, m.peer_chat_min_version, m.peer_chat_max_version, m.member_role, m.member_category, m.member_status, m.show_messages, m.member_restriction,
|
||||
m.invited_by, m.invited_by_group_member_id, m.local_display_name, m.contact_id, m.contact_profile_id, p.contact_profile_id, p.display_name, p.full_name, p.image, p.contact_link, p.local_alias, p.preferences,
|
||||
m.invited_by, m.invited_by_group_member_id, m.local_display_name, m.contact_id, m.contact_profile_id, p.contact_profile_id, p.display_name, p.full_name, p.short_descr, p.image, p.contact_link, p.local_alias, p.preferences,
|
||||
m.created_at, m.updated_at,
|
||||
m.support_chat_ts, m.support_chat_items_unread, m.support_chat_items_member_attention, m.support_chat_items_mentions, m.support_chat_last_msg_from_member_ts,
|
||||
c.connection_id, c.agent_conn_id, c.conn_level, c.via_contact, c.via_user_contact_link, c.via_group_link, c.group_link_id, c.xcontact_id, c.custom_user_profile_id,
|
||||
@@ -4844,7 +4829,7 @@ SEARCH cc USING COVERING INDEX idx_connections_group_member (user_id=? AND group
|
||||
Query:
|
||||
SELECT
|
||||
m.group_member_id, m.group_id, m.member_id, m.peer_chat_min_version, m.peer_chat_max_version, m.member_role, m.member_category, m.member_status, m.show_messages, m.member_restriction,
|
||||
m.invited_by, m.invited_by_group_member_id, m.local_display_name, m.contact_id, m.contact_profile_id, p.contact_profile_id, p.display_name, p.full_name, p.image, p.contact_link, p.local_alias, p.preferences,
|
||||
m.invited_by, m.invited_by_group_member_id, m.local_display_name, m.contact_id, m.contact_profile_id, p.contact_profile_id, p.display_name, p.full_name, p.short_descr, p.image, p.contact_link, p.local_alias, p.preferences,
|
||||
m.created_at, m.updated_at,
|
||||
m.support_chat_ts, m.support_chat_items_unread, m.support_chat_items_member_attention, m.support_chat_items_mentions, m.support_chat_last_msg_from_member_ts,
|
||||
c.connection_id, c.agent_conn_id, c.conn_level, c.via_contact, c.via_user_contact_link, c.via_group_link, c.group_link_id, c.xcontact_id, c.custom_user_profile_id,
|
||||
@@ -4869,7 +4854,7 @@ SEARCH cc USING COVERING INDEX idx_connections_group_member (user_id=? AND group
|
||||
Query:
|
||||
SELECT
|
||||
m.group_member_id, m.group_id, m.member_id, m.peer_chat_min_version, m.peer_chat_max_version, m.member_role, m.member_category, m.member_status, m.show_messages, m.member_restriction,
|
||||
m.invited_by, m.invited_by_group_member_id, m.local_display_name, m.contact_id, m.contact_profile_id, p.contact_profile_id, p.display_name, p.full_name, p.image, p.contact_link, p.local_alias, p.preferences,
|
||||
m.invited_by, m.invited_by_group_member_id, m.local_display_name, m.contact_id, m.contact_profile_id, p.contact_profile_id, p.display_name, p.full_name, p.short_descr, p.image, p.contact_link, p.local_alias, p.preferences,
|
||||
m.created_at, m.updated_at,
|
||||
m.support_chat_ts, m.support_chat_items_unread, m.support_chat_items_member_attention, m.support_chat_items_mentions, m.support_chat_last_msg_from_member_ts,
|
||||
c.connection_id, c.agent_conn_id, c.conn_level, c.via_contact, c.via_user_contact_link, c.via_group_link, c.group_link_id, c.xcontact_id, c.custom_user_profile_id,
|
||||
@@ -4894,7 +4879,7 @@ SEARCH cc USING COVERING INDEX idx_connections_group_member (user_id=? AND group
|
||||
Query:
|
||||
SELECT
|
||||
m.group_member_id, m.group_id, m.member_id, m.peer_chat_min_version, m.peer_chat_max_version, m.member_role, m.member_category, m.member_status, m.show_messages, m.member_restriction,
|
||||
m.invited_by, m.invited_by_group_member_id, m.local_display_name, m.contact_id, m.contact_profile_id, p.contact_profile_id, p.display_name, p.full_name, p.image, p.contact_link, p.local_alias, p.preferences,
|
||||
m.invited_by, m.invited_by_group_member_id, m.local_display_name, m.contact_id, m.contact_profile_id, p.contact_profile_id, p.display_name, p.full_name, p.short_descr, p.image, p.contact_link, p.local_alias, p.preferences,
|
||||
m.created_at, m.updated_at,
|
||||
m.support_chat_ts, m.support_chat_items_unread, m.support_chat_items_member_attention, m.support_chat_items_mentions, m.support_chat_last_msg_from_member_ts,
|
||||
c.connection_id, c.agent_conn_id, c.conn_level, c.via_contact, c.via_user_contact_link, c.via_group_link, c.group_link_id, c.xcontact_id, c.custom_user_profile_id,
|
||||
@@ -4919,7 +4904,7 @@ SEARCH cc USING COVERING INDEX idx_connections_group_member (user_id=? AND group
|
||||
Query:
|
||||
SELECT
|
||||
m.group_member_id, m.group_id, m.member_id, m.peer_chat_min_version, m.peer_chat_max_version, m.member_role, m.member_category, m.member_status, m.show_messages, m.member_restriction,
|
||||
m.invited_by, m.invited_by_group_member_id, m.local_display_name, m.contact_id, m.contact_profile_id, p.contact_profile_id, p.display_name, p.full_name, p.image, p.contact_link, p.local_alias, p.preferences,
|
||||
m.invited_by, m.invited_by_group_member_id, m.local_display_name, m.contact_id, m.contact_profile_id, p.contact_profile_id, p.display_name, p.full_name, p.short_descr, p.image, p.contact_link, p.local_alias, p.preferences,
|
||||
m.created_at, m.updated_at,
|
||||
m.support_chat_ts, m.support_chat_items_unread, m.support_chat_items_member_attention, m.support_chat_items_mentions, m.support_chat_last_msg_from_member_ts,
|
||||
c.connection_id, c.agent_conn_id, c.conn_level, c.via_contact, c.via_user_contact_link, c.via_group_link, c.group_link_id, c.xcontact_id, c.custom_user_profile_id,
|
||||
@@ -5065,7 +5050,7 @@ Plan:
|
||||
SEARCH server_operators USING INTEGER PRIMARY KEY (rowid=?)
|
||||
|
||||
Query:
|
||||
SELECT u.user_id, u.agent_user_id, u.contact_id, ucp.contact_profile_id, u.active_user, u.active_order, u.local_display_name, ucp.full_name, ucp.image, ucp.contact_link, ucp.preferences,
|
||||
SELECT u.user_id, u.agent_user_id, u.contact_id, ucp.contact_profile_id, u.active_user, u.active_order, u.local_display_name, ucp.full_name, ucp.short_descr, ucp.image, ucp.contact_link, ucp.preferences,
|
||||
u.show_ntfs, u.send_rcpts_contacts, u.send_rcpts_small_groups, u.view_pwd_hash, u.view_pwd_salt, u.user_member_profile_updated_at, u.ui_themes
|
||||
FROM users u
|
||||
JOIN contacts uct ON uct.contact_id = u.contact_id
|
||||
@@ -5077,7 +5062,7 @@ SEARCH uct USING INTEGER PRIMARY KEY (rowid=?)
|
||||
SEARCH ucp USING INTEGER PRIMARY KEY (rowid=?)
|
||||
|
||||
Query:
|
||||
SELECT u.user_id, u.agent_user_id, u.contact_id, ucp.contact_profile_id, u.active_user, u.active_order, u.local_display_name, ucp.full_name, ucp.image, ucp.contact_link, ucp.preferences,
|
||||
SELECT u.user_id, u.agent_user_id, u.contact_id, ucp.contact_profile_id, u.active_user, u.active_order, u.local_display_name, ucp.full_name, ucp.short_descr, ucp.image, ucp.contact_link, ucp.preferences,
|
||||
u.show_ntfs, u.send_rcpts_contacts, u.send_rcpts_small_groups, u.view_pwd_hash, u.view_pwd_salt, u.user_member_profile_updated_at, u.ui_themes
|
||||
FROM users u
|
||||
JOIN contacts uct ON uct.contact_id = u.contact_id
|
||||
@@ -5090,7 +5075,7 @@ SEARCH uct USING INTEGER PRIMARY KEY (rowid=?)
|
||||
SEARCH ucp USING INTEGER PRIMARY KEY (rowid=?)
|
||||
|
||||
Query:
|
||||
SELECT u.user_id, u.agent_user_id, u.contact_id, ucp.contact_profile_id, u.active_user, u.active_order, u.local_display_name, ucp.full_name, ucp.image, ucp.contact_link, ucp.preferences,
|
||||
SELECT u.user_id, u.agent_user_id, u.contact_id, ucp.contact_profile_id, u.active_user, u.active_order, u.local_display_name, ucp.full_name, ucp.short_descr, ucp.image, ucp.contact_link, ucp.preferences,
|
||||
u.show_ntfs, u.send_rcpts_contacts, u.send_rcpts_small_groups, u.view_pwd_hash, u.view_pwd_salt, u.user_member_profile_updated_at, u.ui_themes
|
||||
FROM users u
|
||||
JOIN contacts uct ON uct.contact_id = u.contact_id
|
||||
@@ -5103,7 +5088,7 @@ SEARCH uct USING INTEGER PRIMARY KEY (rowid=?)
|
||||
SEARCH ucp USING INTEGER PRIMARY KEY (rowid=?)
|
||||
|
||||
Query:
|
||||
SELECT u.user_id, u.agent_user_id, u.contact_id, ucp.contact_profile_id, u.active_user, u.active_order, u.local_display_name, ucp.full_name, ucp.image, ucp.contact_link, ucp.preferences,
|
||||
SELECT u.user_id, u.agent_user_id, u.contact_id, ucp.contact_profile_id, u.active_user, u.active_order, u.local_display_name, ucp.full_name, ucp.short_descr, ucp.image, ucp.contact_link, ucp.preferences,
|
||||
u.show_ntfs, u.send_rcpts_contacts, u.send_rcpts_small_groups, u.view_pwd_hash, u.view_pwd_salt, u.user_member_profile_updated_at, u.ui_themes
|
||||
FROM users u
|
||||
JOIN contacts uct ON uct.contact_id = u.contact_id
|
||||
@@ -5117,7 +5102,7 @@ SEARCH uct USING INTEGER PRIMARY KEY (rowid=?)
|
||||
SEARCH ucp USING INTEGER PRIMARY KEY (rowid=?)
|
||||
|
||||
Query:
|
||||
SELECT u.user_id, u.agent_user_id, u.contact_id, ucp.contact_profile_id, u.active_user, u.active_order, u.local_display_name, ucp.full_name, ucp.image, ucp.contact_link, ucp.preferences,
|
||||
SELECT u.user_id, u.agent_user_id, u.contact_id, ucp.contact_profile_id, u.active_user, u.active_order, u.local_display_name, ucp.full_name, ucp.short_descr, ucp.image, ucp.contact_link, ucp.preferences,
|
||||
u.show_ntfs, u.send_rcpts_contacts, u.send_rcpts_small_groups, u.view_pwd_hash, u.view_pwd_salt, u.user_member_profile_updated_at, u.ui_themes
|
||||
FROM users u
|
||||
JOIN contacts uct ON uct.contact_id = u.contact_id
|
||||
@@ -5130,7 +5115,7 @@ SEARCH uct USING INTEGER PRIMARY KEY (rowid=?)
|
||||
SEARCH ucp USING INTEGER PRIMARY KEY (rowid=?)
|
||||
|
||||
Query:
|
||||
SELECT u.user_id, u.agent_user_id, u.contact_id, ucp.contact_profile_id, u.active_user, u.active_order, u.local_display_name, ucp.full_name, ucp.image, ucp.contact_link, ucp.preferences,
|
||||
SELECT u.user_id, u.agent_user_id, u.contact_id, ucp.contact_profile_id, u.active_user, u.active_order, u.local_display_name, ucp.full_name, ucp.short_descr, ucp.image, ucp.contact_link, ucp.preferences,
|
||||
u.show_ntfs, u.send_rcpts_contacts, u.send_rcpts_small_groups, u.view_pwd_hash, u.view_pwd_salt, u.user_member_profile_updated_at, u.ui_themes
|
||||
FROM users u
|
||||
JOIN contacts uct ON uct.contact_id = u.contact_id
|
||||
@@ -5143,7 +5128,7 @@ SEARCH uct USING INTEGER PRIMARY KEY (rowid=?)
|
||||
SEARCH ucp USING INTEGER PRIMARY KEY (rowid=?)
|
||||
|
||||
Query:
|
||||
SELECT u.user_id, u.agent_user_id, u.contact_id, ucp.contact_profile_id, u.active_user, u.active_order, u.local_display_name, ucp.full_name, ucp.image, ucp.contact_link, ucp.preferences,
|
||||
SELECT u.user_id, u.agent_user_id, u.contact_id, ucp.contact_profile_id, u.active_user, u.active_order, u.local_display_name, ucp.full_name, ucp.short_descr, ucp.image, ucp.contact_link, ucp.preferences,
|
||||
u.show_ntfs, u.send_rcpts_contacts, u.send_rcpts_small_groups, u.view_pwd_hash, u.view_pwd_salt, u.user_member_profile_updated_at, u.ui_themes
|
||||
FROM users u
|
||||
JOIN contacts uct ON uct.contact_id = u.contact_id
|
||||
@@ -5156,7 +5141,7 @@ SEARCH uct USING INTEGER PRIMARY KEY (rowid=?)
|
||||
SEARCH ucp USING INTEGER PRIMARY KEY (rowid=?)
|
||||
|
||||
Query:
|
||||
SELECT u.user_id, u.agent_user_id, u.contact_id, ucp.contact_profile_id, u.active_user, u.active_order, u.local_display_name, ucp.full_name, ucp.image, ucp.contact_link, ucp.preferences,
|
||||
SELECT u.user_id, u.agent_user_id, u.contact_id, ucp.contact_profile_id, u.active_user, u.active_order, u.local_display_name, ucp.full_name, ucp.short_descr, ucp.image, ucp.contact_link, ucp.preferences,
|
||||
u.show_ntfs, u.send_rcpts_contacts, u.send_rcpts_small_groups, u.view_pwd_hash, u.view_pwd_salt, u.user_member_profile_updated_at, u.ui_themes
|
||||
FROM users u
|
||||
JOIN contacts uct ON uct.contact_id = u.contact_id
|
||||
@@ -5169,7 +5154,7 @@ SEARCH uct USING INTEGER PRIMARY KEY (rowid=?)
|
||||
SEARCH ucp USING INTEGER PRIMARY KEY (rowid=?)
|
||||
|
||||
Query:
|
||||
SELECT u.user_id, u.agent_user_id, u.contact_id, ucp.contact_profile_id, u.active_user, u.active_order, u.local_display_name, ucp.full_name, ucp.image, ucp.contact_link, ucp.preferences,
|
||||
SELECT u.user_id, u.agent_user_id, u.contact_id, ucp.contact_profile_id, u.active_user, u.active_order, u.local_display_name, ucp.full_name, ucp.short_descr, ucp.image, ucp.contact_link, ucp.preferences,
|
||||
u.show_ntfs, u.send_rcpts_contacts, u.send_rcpts_small_groups, u.view_pwd_hash, u.view_pwd_salt, u.user_member_profile_updated_at, u.ui_themes
|
||||
FROM users u
|
||||
JOIN contacts uct ON uct.contact_id = u.contact_id
|
||||
@@ -5633,15 +5618,15 @@ Plan:
|
||||
Query: INSERT INTO chat_item_messages (chat_item_id, message_id, created_at, updated_at) VALUES (?,?,?,?)
|
||||
Plan:
|
||||
|
||||
Query: INSERT INTO contact_profiles (display_name, full_name, image, contact_link, user_id, local_alias, preferences, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?,?)
|
||||
Query: INSERT INTO contact_profiles (display_name, full_name, short_descr, image, contact_link, user_id, local_alias, preferences, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?,?,?)
|
||||
Plan:
|
||||
SEARCH contact_requests USING COVERING INDEX idx_contact_requests_contact_profile_id (contact_profile_id=?)
|
||||
|
||||
Query: INSERT INTO contact_profiles (display_name, full_name, image, contact_link, user_id, preferences, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?)
|
||||
Query: INSERT INTO contact_profiles (display_name, full_name, short_descr, image, contact_link, user_id, preferences, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?,?)
|
||||
Plan:
|
||||
SEARCH contact_requests USING COVERING INDEX idx_contact_requests_contact_profile_id (contact_profile_id=?)
|
||||
|
||||
Query: INSERT INTO contact_profiles (display_name, full_name, image, user_id, preferences, created_at, updated_at) VALUES (?,?,?,?,?,?,?)
|
||||
Query: INSERT INTO contact_profiles (display_name, full_name, short_descr, image, user_id, preferences, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?)
|
||||
Plan:
|
||||
SEARCH contact_requests USING COVERING INDEX idx_contact_requests_contact_profile_id (contact_profile_id=?)
|
||||
|
||||
@@ -5677,10 +5662,10 @@ Plan:
|
||||
Query: INSERT INTO files (user_id, group_id, file_name, file_size, chunk_size, file_inline, ci_file_status, protocol, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?,?,?)
|
||||
Plan:
|
||||
|
||||
Query: INSERT INTO group_profiles (display_name, full_name, description, image, user_id, preferences, member_admission, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?,?)
|
||||
Query: INSERT INTO group_profiles (display_name, full_name, short_descr, description, image, user_id, preferences, member_admission, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?,?,?)
|
||||
Plan:
|
||||
|
||||
Query: INSERT INTO group_profiles (display_name, full_name, image, user_id, preferences, created_at, updated_at) VALUES (?,?,?,?,?,?,?)
|
||||
Query: INSERT INTO group_profiles (display_name, full_name, short_descr, image, user_id, preferences, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?)
|
||||
Plan:
|
||||
|
||||
Query: INSERT INTO group_snd_item_statuses (chat_item_id, group_member_id, group_snd_item_status) VALUES (?,?,?)
|
||||
|
||||
@@ -18,7 +18,8 @@ CREATE TABLE contact_profiles(
|
||||
incognito INTEGER,
|
||||
local_alias TEXT DEFAULT '' CHECK(local_alias NOT NULL),
|
||||
preferences TEXT,
|
||||
contact_link BLOB
|
||||
contact_link BLOB,
|
||||
short_descr TEXT
|
||||
);
|
||||
CREATE TABLE users(
|
||||
user_id INTEGER PRIMARY KEY,
|
||||
@@ -114,7 +115,8 @@ CREATE TABLE group_profiles(
|
||||
user_id INTEGER DEFAULT NULL REFERENCES users ON DELETE CASCADE,
|
||||
preferences TEXT,
|
||||
description TEXT NULL,
|
||||
member_admission TEXT
|
||||
member_admission TEXT,
|
||||
short_descr TEXT
|
||||
);
|
||||
CREATE TABLE groups(
|
||||
group_id INTEGER PRIMARY KEY, -- local group ID
|
||||
|
||||
@@ -293,14 +293,14 @@ createConnection_ db userId connType entityId acId connStatus connChatVersion pe
|
||||
ent ct = if connType == ct then entityId else Nothing
|
||||
|
||||
createIncognitoProfile_ :: DB.Connection -> UserId -> UTCTime -> Profile -> IO Int64
|
||||
createIncognitoProfile_ db userId createdAt Profile {displayName, fullName, image} = do
|
||||
createIncognitoProfile_ db userId createdAt Profile {displayName, fullName, shortDescr, image} = do
|
||||
DB.execute
|
||||
db
|
||||
[sql|
|
||||
INSERT INTO contact_profiles (display_name, full_name, image, user_id, incognito, created_at, updated_at)
|
||||
VALUES (?,?,?,?,?,?,?)
|
||||
INSERT INTO contact_profiles (display_name, full_name, short_descr, image, user_id, incognito, created_at, updated_at)
|
||||
VALUES (?,?,?,?,?,?,?,?)
|
||||
|]
|
||||
(displayName, fullName, image, userId, Just (BI True), createdAt, createdAt)
|
||||
(displayName, fullName, shortDescr, image, userId, Just (BI True), createdAt, createdAt)
|
||||
insertedRowId db
|
||||
|
||||
updateConnSupportPQ :: DB.Connection -> Int64 -> PQSupport -> PQEncryption -> IO ()
|
||||
@@ -387,12 +387,12 @@ createContact db User {userId} profile = do
|
||||
void $ createContact_ db userId profile Nothing "" Nothing currentTs
|
||||
|
||||
createContact_ :: DB.Connection -> UserId -> Profile -> Maybe (ACreatedConnLink, Maybe SharedMsgId) -> LocalAlias -> Maybe Int64 -> UTCTime -> ExceptT StoreError IO (Text, ContactId, ProfileId)
|
||||
createContact_ db userId Profile {displayName, fullName, image, contactLink, preferences} prepared localAlias viaGroup currentTs =
|
||||
createContact_ db userId Profile {displayName, fullName, shortDescr, image, contactLink, preferences} prepared localAlias viaGroup currentTs =
|
||||
ExceptT . withLocalDisplayName db userId displayName $ \ldn -> do
|
||||
DB.execute
|
||||
db
|
||||
"INSERT INTO contact_profiles (display_name, full_name, image, contact_link, user_id, local_alias, preferences, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?,?)"
|
||||
(displayName, fullName, image, contactLink, userId, localAlias, preferences, currentTs, currentTs)
|
||||
"INSERT INTO contact_profiles (display_name, full_name, short_descr, image, contact_link, user_id, local_alias, preferences, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?,?,?)"
|
||||
(displayName, fullName, shortDescr, image, contactLink, userId, localAlias, preferences, currentTs, currentTs)
|
||||
profileId <- insertedRowId db
|
||||
DB.execute
|
||||
db
|
||||
@@ -436,13 +436,13 @@ deleteUnusedIncognitoProfileById_ db User {userId} profileId =
|
||||
|
||||
type PreparedContactRow = (Maybe AConnectionRequestUri, Maybe AConnShortLink, Maybe SharedMsgId, Maybe SharedMsgId)
|
||||
|
||||
type ContactRow' = (ProfileId, ContactName, Maybe Int64, ContactName, Text, Maybe ImageData, Maybe ConnLinkContact, LocalAlias, BoolInt, ContactStatus) :. (Maybe MsgFilter, Maybe BoolInt, BoolInt, Maybe Preferences, Preferences, UTCTime, UTCTime, Maybe UTCTime) :. PreparedContactRow :. (Maybe Int64, Maybe GroupMemberId, BoolInt, Maybe UIThemeEntityOverrides, BoolInt, Maybe CustomData, Maybe Int64)
|
||||
type ContactRow' = (ProfileId, ContactName, Maybe Int64, ContactName, Text, Maybe Text, Maybe ImageData, Maybe ConnLinkContact, LocalAlias, BoolInt, ContactStatus) :. (Maybe MsgFilter, Maybe BoolInt, BoolInt, Maybe Preferences, Preferences, UTCTime, UTCTime, Maybe UTCTime) :. PreparedContactRow :. (Maybe Int64, Maybe GroupMemberId, BoolInt, Maybe UIThemeEntityOverrides, BoolInt, Maybe CustomData, Maybe Int64)
|
||||
|
||||
type ContactRow = Only ContactId :. ContactRow'
|
||||
|
||||
toContact :: VersionRangeChat -> User -> [ChatTagId] -> ContactRow :. MaybeConnectionRow -> Contact
|
||||
toContact vr user chatTags ((Only contactId :. (profileId, localDisplayName, viaGroup, displayName, fullName, image, contactLink, localAlias, BI contactUsed, contactStatus) :. (enableNtfs_, sendRcpts, BI favorite, preferences, userPreferences, createdAt, updatedAt, chatTs) :. preparedContactRow :. (contactRequestId, contactGroupMemberId, BI contactGrpInvSent, uiThemes, BI chatDeleted, customData, chatItemTTL)) :. connRow) =
|
||||
let profile = LocalProfile {profileId, displayName, fullName, image, contactLink, preferences, localAlias}
|
||||
toContact vr user chatTags ((Only contactId :. (profileId, localDisplayName, viaGroup, displayName, fullName, shortDescr, image, contactLink, localAlias, BI contactUsed, contactStatus) :. (enableNtfs_, sendRcpts, BI favorite, preferences, userPreferences, createdAt, updatedAt, chatTs) :. preparedContactRow :. (contactRequestId, contactGroupMemberId, BI contactGrpInvSent, uiThemes, BI chatDeleted, customData, chatItemTTL)) :. connRow) =
|
||||
let profile = LocalProfile {profileId, displayName, fullName, shortDescr, image, contactLink, preferences, localAlias}
|
||||
activeConn = toMaybeConnection vr connRow
|
||||
chatSettings = ChatSettings {enableNtfs = fromMaybe MFAll enableNtfs_, sendRcpts = unBI <$> sendRcpts, favorite}
|
||||
incognito = maybe False connIncognito activeConn
|
||||
@@ -463,42 +463,39 @@ toACreatedConnLink_ (Just (ACR m cr)) csl = case csl of
|
||||
|
||||
getProfileById :: DB.Connection -> UserId -> Int64 -> ExceptT StoreError IO LocalProfile
|
||||
getProfileById db userId profileId =
|
||||
ExceptT . firstRow toProfile (SEProfileNotFound profileId) $
|
||||
ExceptT . firstRow rowToLocalProfile (SEProfileNotFound profileId) $
|
||||
DB.query
|
||||
db
|
||||
[sql|
|
||||
SELECT cp.display_name, cp.full_name, cp.image, cp.contact_link, cp.local_alias, cp.preferences -- , ct.user_preferences
|
||||
SELECT cp.contact_profile_id, cp.display_name, cp.full_name, cp.short_descr, cp.image, cp.contact_link, cp.local_alias, cp.preferences -- , ct.user_preferences
|
||||
FROM contact_profiles cp
|
||||
WHERE cp.user_id = ? AND cp.contact_profile_id = ?
|
||||
|]
|
||||
(userId, profileId)
|
||||
where
|
||||
toProfile :: (ContactName, Text, Maybe ImageData, Maybe ConnLinkContact, LocalAlias, Maybe Preferences) -> LocalProfile
|
||||
toProfile (displayName, fullName, image, contactLink, localAlias, preferences) = LocalProfile {profileId, displayName, fullName, image, contactLink, preferences, localAlias}
|
||||
|
||||
type ContactRequestRow = (Int64, ContactName, AgentInvId, Maybe ContactId, Maybe GroupId, Maybe Int64) :. (Int64, ContactName, Text, Maybe ImageData, Maybe ConnLinkContact) :. (Maybe XContactId, PQSupport, Maybe SharedMsgId, Maybe SharedMsgId, Maybe Preferences, UTCTime, UTCTime, VersionChat, VersionChat)
|
||||
type ContactRequestRow = (Int64, ContactName, AgentInvId, Maybe ContactId, Maybe GroupId, Maybe Int64) :. (Int64, ContactName, Text, Maybe Text, Maybe ImageData, Maybe ConnLinkContact) :. (Maybe XContactId, PQSupport, Maybe SharedMsgId, Maybe SharedMsgId, Maybe Preferences, UTCTime, UTCTime, VersionChat, VersionChat)
|
||||
|
||||
toContactRequest :: ContactRequestRow -> UserContactRequest
|
||||
toContactRequest ((contactRequestId, localDisplayName, agentInvitationId, contactId_, businessGroupId_, userContactLinkId_) :. (profileId, displayName, fullName, image, contactLink) :. (xContactId, pqSupport, welcomeSharedMsgId, requestSharedMsgId, preferences, createdAt, updatedAt, minVer, maxVer)) = do
|
||||
let profile = Profile {displayName, fullName, image, contactLink, preferences}
|
||||
toContactRequest ((contactRequestId, localDisplayName, agentInvitationId, contactId_, businessGroupId_, userContactLinkId_) :. (profileId, displayName, fullName, shortDescr, image, contactLink) :. (xContactId, pqSupport, welcomeSharedMsgId, requestSharedMsgId, preferences, createdAt, updatedAt, minVer, maxVer)) = do
|
||||
let profile = Profile {displayName, fullName, shortDescr, image, contactLink, preferences}
|
||||
cReqChatVRange = fromMaybe (versionToRange maxVer) $ safeVersionRange minVer maxVer
|
||||
in UserContactRequest {contactRequestId, agentInvitationId, contactId_, businessGroupId_, userContactLinkId_, cReqChatVRange, localDisplayName, profileId, profile, xContactId, pqSupport, welcomeSharedMsgId, requestSharedMsgId, createdAt, updatedAt}
|
||||
|
||||
userQuery :: Query
|
||||
userQuery =
|
||||
[sql|
|
||||
SELECT u.user_id, u.agent_user_id, u.contact_id, ucp.contact_profile_id, u.active_user, u.active_order, u.local_display_name, ucp.full_name, ucp.image, ucp.contact_link, ucp.preferences,
|
||||
SELECT u.user_id, u.agent_user_id, u.contact_id, ucp.contact_profile_id, u.active_user, u.active_order, u.local_display_name, ucp.full_name, ucp.short_descr, ucp.image, ucp.contact_link, ucp.preferences,
|
||||
u.show_ntfs, u.send_rcpts_contacts, u.send_rcpts_small_groups, u.view_pwd_hash, u.view_pwd_salt, u.user_member_profile_updated_at, u.ui_themes
|
||||
FROM users u
|
||||
JOIN contacts uct ON uct.contact_id = u.contact_id
|
||||
JOIN contact_profiles ucp ON ucp.contact_profile_id = uct.contact_profile_id
|
||||
|]
|
||||
|
||||
toUser :: (UserId, UserId, ContactId, ProfileId, BoolInt, Int64, ContactName, Text, Maybe ImageData, Maybe ConnLinkContact, Maybe Preferences) :. (BoolInt, BoolInt, BoolInt, Maybe B64UrlByteString, Maybe B64UrlByteString, Maybe UTCTime, Maybe UIThemeEntityOverrides) -> User
|
||||
toUser ((userId, auId, userContactId, profileId, BI activeUser, activeOrder, displayName, fullName, image, contactLink, userPreferences) :. (BI showNtfs, BI sendRcptsContacts, BI sendRcptsSmallGroups, viewPwdHash_, viewPwdSalt_, userMemberProfileUpdatedAt, uiThemes)) =
|
||||
toUser :: (UserId, UserId, ContactId, ProfileId, BoolInt, Int64, ContactName, Text, Maybe Text, Maybe ImageData, Maybe ConnLinkContact, Maybe Preferences) :. (BoolInt, BoolInt, BoolInt, Maybe B64UrlByteString, Maybe B64UrlByteString, Maybe UTCTime, Maybe UIThemeEntityOverrides) -> User
|
||||
toUser ((userId, auId, userContactId, profileId, BI activeUser, activeOrder, displayName, fullName, shortDescr, image, contactLink, userPreferences) :. (BI showNtfs, BI sendRcptsContacts, BI sendRcptsSmallGroups, viewPwdHash_, viewPwdSalt_, userMemberProfileUpdatedAt, uiThemes)) =
|
||||
User {userId, agentUserId = AgentUserId auId, userContactId, localDisplayName = displayName, profile, activeUser, activeOrder, fullPreferences, showNtfs, sendRcptsContacts, sendRcptsSmallGroups, viewPwdHash, userMemberProfileUpdatedAt, uiThemes}
|
||||
where
|
||||
profile = LocalProfile {profileId, displayName, fullName, image, contactLink, preferences = userPreferences, localAlias = ""}
|
||||
profile = LocalProfile {profileId, displayName, fullName, shortDescr, image, contactLink, preferences = userPreferences, localAlias = ""}
|
||||
fullPreferences = mergePreferences Nothing userPreferences
|
||||
viewPwdHash = UserPwdHash <$> viewPwdHash_ <*> viewPwdSalt_
|
||||
|
||||
@@ -612,16 +609,18 @@ type PreparedGroupRow = (Maybe ConnReqContact, Maybe ShortLinkContact, BoolInt,
|
||||
|
||||
type BusinessChatInfoRow = (Maybe BusinessChatType, Maybe MemberId, Maybe MemberId)
|
||||
|
||||
type GroupInfoRow = (Int64, GroupName, GroupName, Text, Text, Maybe Text, Maybe ImageData, Maybe MsgFilter, Maybe BoolInt, BoolInt, Maybe GroupPreferences, Maybe GroupMemberAdmission) :. (UTCTime, UTCTime, Maybe UTCTime, Maybe UTCTime) :. PreparedGroupRow :. BusinessChatInfoRow :. (Maybe UIThemeEntityOverrides, Maybe CustomData, Maybe Int64, Int) :. GroupMemberRow
|
||||
type GroupInfoRow = (Int64, GroupName, GroupName, Text, Maybe Text, Text, Maybe Text, Maybe ImageData) :. (Maybe MsgFilter, Maybe BoolInt, BoolInt, Maybe GroupPreferences, Maybe GroupMemberAdmission) :. (UTCTime, UTCTime, Maybe UTCTime, Maybe UTCTime) :. PreparedGroupRow :. BusinessChatInfoRow :. (Maybe UIThemeEntityOverrides, Maybe CustomData, Maybe Int64, Int) :. GroupMemberRow
|
||||
|
||||
type GroupMemberRow = (Int64, Int64, MemberId, VersionChat, VersionChat, GroupMemberRole, GroupMemberCategory, GroupMemberStatus, BoolInt, Maybe MemberRestrictionStatus) :. (Maybe Int64, Maybe GroupMemberId, ContactName, Maybe ContactId, ProfileId, ProfileId, ContactName, Text, Maybe ImageData, Maybe ConnLinkContact, LocalAlias, Maybe Preferences) :. (UTCTime, UTCTime) :. (Maybe UTCTime, Int64, Int64, Int64, Maybe UTCTime)
|
||||
type GroupMemberRow = (Int64, Int64, MemberId, VersionChat, VersionChat, GroupMemberRole, GroupMemberCategory, GroupMemberStatus, BoolInt, Maybe MemberRestrictionStatus) :. (Maybe Int64, Maybe GroupMemberId, ContactName, Maybe ContactId, ProfileId) :. ProfileRow :. (UTCTime, UTCTime) :. (Maybe UTCTime, Int64, Int64, Int64, Maybe UTCTime)
|
||||
|
||||
type ProfileRow = (ProfileId, ContactName, Text, Maybe Text, Maybe ImageData, Maybe ConnLinkContact, LocalAlias, Maybe Preferences)
|
||||
|
||||
toGroupInfo :: VersionRangeChat -> Int64 -> [ChatTagId] -> GroupInfoRow -> GroupInfo
|
||||
toGroupInfo vr userContactId chatTags ((groupId, localDisplayName, displayName, fullName, localAlias, description, image, enableNtfs_, sendRcpts, BI favorite, groupPreferences, memberAdmission) :. (createdAt, updatedAt, chatTs, userMemberProfileSentAt) :. preparedGroupRow :. businessRow :. (uiThemes, customData, chatItemTTL, membersRequireAttention) :. userMemberRow) =
|
||||
toGroupInfo vr userContactId chatTags ((groupId, localDisplayName, displayName, fullName, shortDescr, localAlias, description, image) :. (enableNtfs_, sendRcpts, BI favorite, groupPreferences, memberAdmission) :. (createdAt, updatedAt, chatTs, userMemberProfileSentAt) :. preparedGroupRow :. businessRow :. (uiThemes, customData, chatItemTTL, membersRequireAttention) :. userMemberRow) =
|
||||
let membership = (toGroupMember userContactId userMemberRow) {memberChatVRange = vr}
|
||||
chatSettings = ChatSettings {enableNtfs = fromMaybe MFAll enableNtfs_, sendRcpts = unBI <$> sendRcpts, favorite}
|
||||
fullGroupPreferences = mergeGroupPreferences groupPreferences
|
||||
groupProfile = GroupProfile {displayName, fullName, description, image, groupPreferences, memberAdmission}
|
||||
groupProfile = GroupProfile {displayName, fullName, shortDescr, description, image, groupPreferences, memberAdmission}
|
||||
businessChat = toBusinessChatInfo businessRow
|
||||
preparedGroup = toPreparedGroup preparedGroupRow
|
||||
in GroupInfo {groupId, localDisplayName, groupProfile, localAlias, businessChat, fullGroupPreferences, membership, chatSettings, createdAt, updatedAt, chatTs, userMemberProfileSentAt, preparedGroup, chatTags, chatItemTTL, uiThemes, customData, membersRequireAttention}
|
||||
@@ -633,8 +632,8 @@ toPreparedGroup = \case
|
||||
_ -> Nothing
|
||||
|
||||
toGroupMember :: Int64 -> GroupMemberRow -> GroupMember
|
||||
toGroupMember userContactId ((groupMemberId, groupId, memberId, minVer, maxVer, memberRole, memberCategory, memberStatus, BI showMessages, memberRestriction_) :. (invitedById, invitedByGroupMemberId, localDisplayName, memberContactId, memberContactProfileId, profileId, displayName, fullName, image, contactLink, localAlias, preferences) :. (createdAt, updatedAt) :. (supportChatTs_, supportChatUnread, supportChatMemberAttention, supportChatMentions, supportChatLastMsgFromMemberTs)) =
|
||||
let memberProfile = LocalProfile {profileId, displayName, fullName, image, contactLink, preferences, localAlias}
|
||||
toGroupMember userContactId ((groupMemberId, groupId, memberId, minVer, maxVer, memberRole, memberCategory, memberStatus, BI showMessages, memberRestriction_) :. (invitedById, invitedByGroupMemberId, localDisplayName, memberContactId, memberContactProfileId) :. profileRow :. (createdAt, updatedAt) :. (supportChatTs_, supportChatUnread, supportChatMemberAttention, supportChatMentions, supportChatLastMsgFromMemberTs)) =
|
||||
let memberProfile = rowToLocalProfile profileRow
|
||||
memberSettings = GroupMemberSettings {showMessages}
|
||||
blockedByAdmin = maybe False mrsBlocked memberRestriction_
|
||||
invitedBy = toInvitedBy userContactId invitedById
|
||||
@@ -652,6 +651,10 @@ toGroupMember userContactId ((groupMemberId, groupId, memberId, minVer, maxVer,
|
||||
_ -> Nothing
|
||||
in GroupMember {..}
|
||||
|
||||
rowToLocalProfile :: ProfileRow -> LocalProfile
|
||||
rowToLocalProfile (profileId, displayName, fullName, shortDescr, image, contactLink, localAlias, preferences) =
|
||||
LocalProfile {profileId, displayName, fullName, shortDescr, image, contactLink, localAlias, preferences}
|
||||
|
||||
toBusinessChatInfo :: BusinessChatInfoRow -> Maybe BusinessChatInfo
|
||||
toBusinessChatInfo (Just chatType, Just businessId, Just customerId) = Just BusinessChatInfo {chatType, businessId, customerId}
|
||||
toBusinessChatInfo _ = Nothing
|
||||
@@ -661,7 +664,7 @@ groupInfoQuery =
|
||||
[sql|
|
||||
SELECT
|
||||
-- GroupInfo
|
||||
g.group_id, g.local_display_name, gp.display_name, gp.full_name, g.local_alias, gp.description, gp.image,
|
||||
g.group_id, g.local_display_name, gp.display_name, gp.full_name, gp.short_descr, g.local_alias, gp.description, gp.image,
|
||||
g.enable_ntfs, g.send_rcpts, g.favorite, gp.preferences, gp.member_admission,
|
||||
g.created_at, g.updated_at, g.chat_ts, g.user_member_profile_sent_at,
|
||||
g.conn_full_link_to_connect, g.conn_short_link_to_connect, g.conn_link_prepared_connection, g.conn_link_started_connection, g.welcome_shared_msg_id, g.request_shared_msg_id,
|
||||
@@ -670,7 +673,7 @@ groupInfoQuery =
|
||||
-- GroupMember - membership
|
||||
mu.group_member_id, mu.group_id, mu.member_id, mu.peer_chat_min_version, mu.peer_chat_max_version, mu.member_role, mu.member_category,
|
||||
mu.member_status, mu.show_messages, mu.member_restriction, mu.invited_by, mu.invited_by_group_member_id, mu.local_display_name, mu.contact_id, mu.contact_profile_id, pu.contact_profile_id,
|
||||
pu.display_name, pu.full_name, pu.image, pu.contact_link, pu.local_alias, pu.preferences,
|
||||
pu.display_name, pu.full_name, pu.short_descr, pu.image, pu.contact_link, pu.local_alias, pu.preferences,
|
||||
mu.created_at, mu.updated_at,
|
||||
mu.support_chat_ts, mu.support_chat_items_unread, mu.support_chat_items_member_attention, mu.support_chat_items_mentions, mu.support_chat_last_msg_from_member_ts
|
||||
FROM groups g
|
||||
|
||||
+14
-11
@@ -422,9 +422,9 @@ type MemberName = Text
|
||||
|
||||
type GroupName = Text
|
||||
|
||||
optionalFullName :: ContactName -> Text -> Text
|
||||
optionalFullName displayName fullName
|
||||
| T.null fullName || displayName == fullName = ""
|
||||
optionalFullName :: ContactName -> Text -> Maybe Text -> Text
|
||||
optionalFullName displayName fullName shortDescr
|
||||
| T.null fullName || displayName == fullName = maybe "" (\sd -> " (" <> sd <> ")") shortDescr
|
||||
| otherwise = " (" <> fullName <> ")"
|
||||
|
||||
data ShortGroup = ShortGroup
|
||||
@@ -620,6 +620,7 @@ contactUserPreferences user userPreferences contactPreferences connectedIncognit
|
||||
data Profile = Profile
|
||||
{ displayName :: ContactName,
|
||||
fullName :: Text,
|
||||
shortDescr :: Maybe Text, -- short description limited to 160 characters
|
||||
image :: Maybe ImageData,
|
||||
contactLink :: Maybe ConnLinkContact,
|
||||
preferences :: Maybe Preferences
|
||||
@@ -632,7 +633,7 @@ data Profile = Profile
|
||||
|
||||
profileFromName :: ContactName -> Profile
|
||||
profileFromName displayName =
|
||||
Profile {displayName, fullName = "", image = Nothing, contactLink = Nothing, preferences = Nothing}
|
||||
Profile {displayName, fullName = "", shortDescr = Nothing, image = Nothing, contactLink = Nothing, preferences = Nothing}
|
||||
|
||||
-- check if profiles match ignoring preferences
|
||||
profilesMatch :: LocalProfile -> LocalProfile -> Bool
|
||||
@@ -642,8 +643,8 @@ profilesMatch
|
||||
n1 == n2 && fn1 == fn2 && i1 == i2
|
||||
|
||||
redactedMemberProfile :: Profile -> Profile
|
||||
redactedMemberProfile Profile {displayName, fullName, image} =
|
||||
Profile {displayName, fullName, image, contactLink = Nothing, preferences = Nothing}
|
||||
redactedMemberProfile Profile {displayName, fullName, shortDescr, image} =
|
||||
Profile {displayName, fullName, shortDescr, image, contactLink = Nothing, preferences = Nothing}
|
||||
|
||||
data IncognitoProfile = NewIncognito Profile | ExistingIncognito LocalProfile
|
||||
|
||||
@@ -669,6 +670,7 @@ data LocalProfile = LocalProfile
|
||||
{ profileId :: ProfileId,
|
||||
displayName :: ContactName,
|
||||
fullName :: Text,
|
||||
shortDescr :: Maybe Text,
|
||||
image :: Maybe ImageData,
|
||||
contactLink :: Maybe ConnLinkContact,
|
||||
preferences :: Maybe Preferences,
|
||||
@@ -680,17 +682,18 @@ localProfileId :: LocalProfile -> ProfileId
|
||||
localProfileId LocalProfile {profileId} = profileId
|
||||
|
||||
toLocalProfile :: ProfileId -> Profile -> LocalAlias -> LocalProfile
|
||||
toLocalProfile profileId Profile {displayName, fullName, image, contactLink, preferences} localAlias =
|
||||
LocalProfile {profileId, displayName, fullName, image, contactLink, preferences, localAlias}
|
||||
toLocalProfile profileId Profile {displayName, fullName, shortDescr, image, contactLink, preferences} localAlias =
|
||||
LocalProfile {profileId, displayName, fullName, shortDescr, image, contactLink, preferences, localAlias}
|
||||
|
||||
fromLocalProfile :: LocalProfile -> Profile
|
||||
fromLocalProfile LocalProfile {displayName, fullName, image, contactLink, preferences} =
|
||||
Profile {displayName, fullName, image, contactLink, preferences}
|
||||
fromLocalProfile LocalProfile {displayName, fullName, shortDescr, image, contactLink, preferences} =
|
||||
Profile {displayName, fullName, shortDescr, image, contactLink, preferences}
|
||||
|
||||
data GroupProfile = GroupProfile
|
||||
{ displayName :: GroupName,
|
||||
fullName :: Text,
|
||||
description :: Maybe Text,
|
||||
shortDescr :: Maybe Text, -- short description limited to 160 characters
|
||||
description :: Maybe Text, -- this has been repurposed as welcome message
|
||||
image :: Maybe ImageData,
|
||||
groupPreferences :: Maybe GroupPreferences,
|
||||
memberAdmission :: Maybe GroupMemberAdmission
|
||||
|
||||
+41
-34
@@ -606,8 +606,8 @@ viewUsersList us =
|
||||
in if null ss then ["no users"] else ss
|
||||
where
|
||||
ldn (UserInfo User {localDisplayName = n} _) = T.toLower n
|
||||
userInfo (UserInfo User {localDisplayName = n, profile = LocalProfile {fullName}, activeUser, showNtfs, viewPwdHash} count)
|
||||
| activeUser || isNothing viewPwdHash = Just $ ttyFullName n fullName <> infoStr
|
||||
userInfo (UserInfo User {localDisplayName = n, profile = LocalProfile {fullName, shortDescr}, activeUser, showNtfs, viewPwdHash} count)
|
||||
| activeUser || isNothing viewPwdHash = Just $ ttyFullName n fullName shortDescr <> infoStr
|
||||
| otherwise = Nothing
|
||||
where
|
||||
infoStr = if null info then "" else " (" <> mconcat (intersperse ", " info) <> ")"
|
||||
@@ -1158,8 +1158,8 @@ viewAcceptingBusinessRequest :: GroupInfo -> [StyledString]
|
||||
viewAcceptingBusinessRequest g = [ttyFullGroup g <> ": accepting business address request..."]
|
||||
|
||||
viewReceivedContactRequest :: ContactName -> Profile -> [StyledString]
|
||||
viewReceivedContactRequest c Profile {fullName} =
|
||||
[ ttyFullName c fullName <> " wants to connect to you!",
|
||||
viewReceivedContactRequest c Profile {fullName, shortDescr} =
|
||||
[ ttyFullName c fullName shortDescr <> " wants to connect to you!",
|
||||
"to accept: " <> highlight ("/ac " <> viewName c),
|
||||
"to reject: " <> highlight ("/rc " <> viewName c) <> " (the sender will NOT be notified)"
|
||||
]
|
||||
@@ -1380,9 +1380,9 @@ viewSentGroupInvitation g c = case contactConn c of
|
||||
Nothing -> []
|
||||
|
||||
groupInvitation' :: GroupInfo -> StyledString
|
||||
groupInvitation' g@GroupInfo {localDisplayName = ldn, groupProfile = GroupProfile {fullName}} =
|
||||
groupInvitation' g@GroupInfo {localDisplayName = ldn, groupProfile = GroupProfile {fullName, shortDescr}} =
|
||||
highlight ("#" <> viewName ldn)
|
||||
<> optFullName ldn fullName
|
||||
<> optFullName ldn fullName shortDescr
|
||||
<> " - you are invited ("
|
||||
<> highlight ("/j " <> viewName ldn)
|
||||
<> joinText
|
||||
@@ -1415,9 +1415,9 @@ viewContactAndMemberAssociated ct g m ct' =
|
||||
]
|
||||
|
||||
viewUserProfile :: Profile -> [StyledString]
|
||||
viewUserProfile Profile {displayName, fullName} =
|
||||
[ "user profile: " <> ttyFullName displayName fullName,
|
||||
"use " <> highlight' "/p <display name>" <> " to change it",
|
||||
viewUserProfile Profile {displayName, fullName, shortDescr} =
|
||||
[ "user profile: " <> ttyFullName displayName fullName shortDescr,
|
||||
"use " <> highlight' "/p <name> [<bio>]" <> " to change it",
|
||||
"(the updated profile will be sent to all your contacts)"
|
||||
]
|
||||
|
||||
@@ -1703,16 +1703,17 @@ viewSwitchPhase = \case
|
||||
SPCompleted -> "changed address"
|
||||
|
||||
viewUserProfileUpdated :: Profile -> Profile -> UserProfileUpdateSummary -> [StyledString]
|
||||
viewUserProfileUpdated Profile {displayName = n, fullName, image, contactLink, preferences} Profile {displayName = n', fullName = fullName', image = image', contactLink = contactLink', preferences = prefs'} summary =
|
||||
viewUserProfileUpdated Profile {displayName = n, fullName, shortDescr, image, contactLink, preferences} Profile {displayName = n', fullName = fullName', shortDescr = shortDescr', image = image', contactLink = contactLink', preferences = prefs'} summary =
|
||||
profileUpdated <> viewPrefsUpdated preferences prefs'
|
||||
where
|
||||
UserProfileUpdateSummary {updateSuccesses = s, updateFailures = f} = summary
|
||||
profileUpdated
|
||||
| n == n' && fullName == fullName' && image == image' && contactLink == contactLink' = []
|
||||
| n == n' && fullName == fullName' && image == image' = [if isNothing contactLink' then "contact address removed" else "new contact address set"]
|
||||
| n == n' && fullName == fullName' = [if isNothing image' then "profile image removed" else "profile image updated"]
|
||||
| n == n' && fullName == fullName' && shortDescr == shortDescr' && image == image' && contactLink == contactLink' = []
|
||||
| n == n' && fullName == fullName' && shortDescr == shortDescr' && image == image' = [if isNothing contactLink' then "contact address removed" else "new contact address set"]
|
||||
| n == n' && fullName == fullName' && shortDescr == shortDescr' = [if isNothing image' then "profile image removed" else "profile image updated"]
|
||||
| n == n' && fullName == fullName' = ["user bio " <> (if maybe True T.null shortDescr' then "removed" else "changed to " <> maybe "" plain shortDescr') <> notified]
|
||||
| n == n' = ["user full name " <> (if T.null fullName' || fullName' == n' then "removed" else "changed to " <> plain fullName') <> notified]
|
||||
| otherwise = ["user profile is changed to " <> ttyFullName n' fullName' <> notified]
|
||||
| otherwise = ["user profile is changed to " <> ttyFullName n' fullName' shortDescr' <> notified]
|
||||
notified = " (your " <> sShow s <> " contacts are notified" <> failures <> ")"
|
||||
failures
|
||||
| f > 0 = ", " <> sShow f <> " failures"
|
||||
@@ -1770,8 +1771,8 @@ countactUserPrefText cup = case cup of
|
||||
|
||||
viewGroupUpdated :: GroupInfo -> GroupInfo -> Maybe GroupMember -> [StyledString]
|
||||
viewGroupUpdated
|
||||
GroupInfo {localDisplayName = n, groupProfile = GroupProfile {fullName, description, image, groupPreferences = gps, memberAdmission = ma}}
|
||||
g'@GroupInfo {localDisplayName = n', groupProfile = GroupProfile {fullName = fullName', description = description', image = image', groupPreferences = gps', memberAdmission = ma'}}
|
||||
GroupInfo {localDisplayName = n, groupProfile = GroupProfile {fullName, shortDescr, description, image, groupPreferences = gps, memberAdmission = ma}}
|
||||
g'@GroupInfo {localDisplayName = n', groupProfile = GroupProfile {fullName = fullName', shortDescr = shortDescr', description = description', image = image', groupPreferences = gps', memberAdmission = ma'}}
|
||||
m = do
|
||||
let update = groupProfileUpdated <> groupPrefsUpdated <> memberAdmissionUpdated
|
||||
if null update
|
||||
@@ -1782,8 +1783,9 @@ viewGroupUpdated
|
||||
groupProfileUpdated =
|
||||
["changed to " <> ttyFullGroup g' | n /= n']
|
||||
<> ["full name " <> if T.null fullName' || fullName' == n' then "removed" else "changed to: " <> plain fullName' | n == n' && fullName /= fullName']
|
||||
<> ["description " <> if maybe True T.null shortDescr' then "removed" else "changed to: " <> maybe "" plain shortDescr' | n == n' && fullName == fullName' && shortDescr /= shortDescr']
|
||||
<> ["profile image " <> maybe "removed" (const "updated") image' | image /= image']
|
||||
<> (if description == description' then [] else maybe ["description removed"] ((bold' "description changed to:" :) . map plain . T.lines) description')
|
||||
<> (if description == description' then [] else maybe ["welcome message removed"] ((bold' "welcome message changed to:" :) . map plain . T.lines) description')
|
||||
groupPrefsUpdated
|
||||
| null prefs = []
|
||||
| otherwise = bold' "updated group preferences:" : prefs
|
||||
@@ -1799,10 +1801,11 @@ viewGroupUpdated
|
||||
| otherwise = ["changed member admission rules"]
|
||||
|
||||
viewGroupProfile :: GroupInfo -> [StyledString]
|
||||
viewGroupProfile g@GroupInfo {groupProfile = GroupProfile {description, image, groupPreferences = gps}} =
|
||||
viewGroupProfile g@GroupInfo {groupProfile = GroupProfile {shortDescr, description, image, groupPreferences = gps}} =
|
||||
[ttyFullGroup g]
|
||||
<> maybe [] (\sd -> ["description: " <> plain sd]) shortDescr
|
||||
<> maybe [] (const ["has profile image"]) image
|
||||
<> maybe [] ((bold' "description:" :) . map plain . T.lines) description
|
||||
<> maybe [] ((bold' "welcome message:" :) . map plain . T.lines) description
|
||||
<> (bold' "group preferences:" : map viewPref allGroupFeatures)
|
||||
where
|
||||
viewPref (AGF f) = plain $ groupPreferenceText (pref gps)
|
||||
@@ -1963,16 +1966,20 @@ viewConnectionPlan ChatConfig {logLevel, testView} _connLink = \case
|
||||
|
||||
viewContactUpdated :: Contact -> Contact -> [StyledString]
|
||||
viewContactUpdated
|
||||
Contact {localDisplayName = n, profile = LocalProfile {fullName, contactLink}}
|
||||
Contact {localDisplayName = n', profile = LocalProfile {fullName = fullName', contactLink = contactLink'}}
|
||||
| n == n' && fullName == fullName' && contactLink == contactLink' = []
|
||||
| n == n' && fullName == fullName' =
|
||||
Contact {localDisplayName = n, profile = LocalProfile {fullName, shortDescr, contactLink}}
|
||||
Contact {localDisplayName = n', profile = LocalProfile {fullName = fullName', shortDescr = shortDescr', contactLink = contactLink'}}
|
||||
| n == n' && fullName == fullName' && shortDescr == shortDescr' && contactLink == contactLink' = []
|
||||
| n == n' && fullName == fullName' && shortDescr == shortDescr' =
|
||||
if isNothing contactLink'
|
||||
then [ttyContact n <> " removed contact address"]
|
||||
else [ttyContact n <> " set new contact address, use " <> highlight ("/info " <> n) <> " to view"]
|
||||
| n == n' && fullName == fullName' =
|
||||
if maybe True T.null shortDescr'
|
||||
then ["contact " <> ttyContact n <> " removed bio"]
|
||||
else ["contact " <> ttyContact n <> " updated bio: " <> maybe "" plain shortDescr']
|
||||
| n == n' = ["contact " <> ttyContact n <> fullNameUpdate]
|
||||
| otherwise =
|
||||
[ "contact " <> ttyContact n <> " changed to " <> ttyFullName n' fullName',
|
||||
[ "contact " <> ttyContact n <> " changed to " <> ttyFullName n' fullName' shortDescr',
|
||||
"use " <> ttyToContact n' <> highlight' "<message>" <> " to send messages"
|
||||
]
|
||||
where
|
||||
@@ -2566,18 +2573,18 @@ ttyContact' :: Contact -> StyledString
|
||||
ttyContact' Contact {localDisplayName = c} = ttyContact c
|
||||
|
||||
ttyFullContact :: Contact -> StyledString
|
||||
ttyFullContact Contact {localDisplayName, profile = LocalProfile {fullName}} =
|
||||
ttyFullName localDisplayName fullName
|
||||
ttyFullContact Contact {localDisplayName, profile = LocalProfile {fullName, shortDescr}} =
|
||||
ttyFullName localDisplayName fullName shortDescr
|
||||
|
||||
ttyMember :: GroupMember -> StyledString
|
||||
ttyMember GroupMember {localDisplayName} = ttyContact localDisplayName
|
||||
|
||||
ttyFullMember :: GroupMember -> StyledString
|
||||
ttyFullMember GroupMember {localDisplayName, memberProfile = LocalProfile {fullName}} =
|
||||
ttyFullName localDisplayName fullName
|
||||
ttyFullMember GroupMember {localDisplayName, memberProfile = LocalProfile {fullName, shortDescr}} =
|
||||
ttyFullName localDisplayName fullName shortDescr
|
||||
|
||||
ttyFullName :: ContactName -> Text -> StyledString
|
||||
ttyFullName c fullName = ttyContact c <> optFullName c fullName
|
||||
ttyFullName :: ContactName -> Text -> Maybe Text -> StyledString
|
||||
ttyFullName c fullName shortDescr = ttyContact c <> optFullName c fullName shortDescr
|
||||
|
||||
ttyToContact :: ContactName -> StyledString
|
||||
ttyToContact c = ttyTo $ "@" <> viewName c <> " "
|
||||
@@ -2626,8 +2633,8 @@ ttyGroups [g] = ttyGroup g
|
||||
ttyGroups (g : gs) = ttyGroup g <> ", " <> ttyGroups gs
|
||||
|
||||
ttyFullGroup :: GroupInfo -> StyledString
|
||||
ttyFullGroup GroupInfo {localDisplayName = g, groupProfile = GroupProfile {fullName}} =
|
||||
ttyGroup g <> optFullName g fullName
|
||||
ttyFullGroup GroupInfo {localDisplayName = g, groupProfile = GroupProfile {fullName, shortDescr}} =
|
||||
ttyGroup g <> optFullName g fullName shortDescr
|
||||
|
||||
ttyFromGroup :: GroupInfo -> Maybe GroupChatScopeInfo -> GroupMember -> StyledString
|
||||
ttyFromGroup g scopeInfo m = ttyFromGroupAttention g scopeInfo m False
|
||||
@@ -2672,8 +2679,8 @@ groupScopeInfoStr = \case
|
||||
ttyFilePath :: FilePath -> StyledString
|
||||
ttyFilePath = plain
|
||||
|
||||
optFullName :: ContactName -> Text -> StyledString
|
||||
optFullName localDisplayName fullName = plain $ optionalFullName localDisplayName fullName
|
||||
optFullName :: ContactName -> Text -> Maybe Text -> StyledString
|
||||
optFullName localDisplayName fullName shortDescr = plain $ optionalFullName localDisplayName fullName shortDescr
|
||||
|
||||
ctIncognito :: Contact -> StyledString
|
||||
ctIncognito ct = if contactConnIncognito ct then incognitoPrefix else ""
|
||||
|
||||
@@ -33,7 +33,7 @@ withBroadcastBot opts test =
|
||||
bot = simplexChatCore testCfg (mkChatOpts opts) $ broadcastBot opts
|
||||
|
||||
broadcastBotProfile :: Profile
|
||||
broadcastBotProfile = Profile {displayName = "broadcast_bot", fullName = "Broadcast Bot", image = Nothing, contactLink = Nothing, preferences = Nothing}
|
||||
broadcastBotProfile = Profile {displayName = "broadcast_bot", fullName = "Broadcast Bot", shortDescr = Nothing, image = Nothing, contactLink = Nothing, preferences = Nothing}
|
||||
|
||||
mkBotOpts :: TestParams -> [KnownContact] -> BroadcastBotOpts
|
||||
mkBotOpts ps publishers =
|
||||
|
||||
@@ -75,7 +75,7 @@ directoryServiceTests = do
|
||||
it "should accept some incorrect spellings" testCaptcha
|
||||
|
||||
directoryProfile :: Profile
|
||||
directoryProfile = Profile {displayName = "SimpleX-Directory", fullName = "", image = Nothing, contactLink = Nothing, preferences = Nothing}
|
||||
directoryProfile = Profile {displayName = "SimpleX-Directory", fullName = "", shortDescr = Nothing, image = Nothing, contactLink = Nothing, preferences = Nothing}
|
||||
|
||||
mkDirectoryOpts :: TestParams -> [KnownContact] -> Maybe KnownGroup -> DirectoryOpts
|
||||
mkDirectoryOpts TestParams {tmpPath = ps} superUsers ownersGroup =
|
||||
@@ -219,7 +219,7 @@ testDirectoryService ps =
|
||||
u <## "2 members"
|
||||
updateGroupProfile u welcome = do
|
||||
u ##> ("/set welcome #PSA " <> welcome)
|
||||
u <## "description changed to:"
|
||||
u <## "welcome message changed to:"
|
||||
u <## welcome
|
||||
approvalRequested su welcome grId = do
|
||||
su <# "SimpleX-Directory> bob submitted the group ID 1:"
|
||||
@@ -738,11 +738,11 @@ testRegOwnerChangedProfile ps =
|
||||
registerGroup superUser bob "privacy" "Privacy"
|
||||
addCathAsOwner bob cath
|
||||
bob ##> "/gp privacy privacy Privacy and Security"
|
||||
bob <## "full name changed to: Privacy and Security"
|
||||
bob <## "description changed to: Privacy and Security"
|
||||
bob <# "SimpleX-Directory> The group ID 1 (privacy) is updated!"
|
||||
bob <## "It is hidden from the directory until approved."
|
||||
cath <## "bob updated group #privacy:"
|
||||
cath <## "full name changed to: Privacy and Security"
|
||||
cath <## "description changed to: Privacy and Security"
|
||||
cath `connectVia` dsLink
|
||||
cath <## "contact and member are merged: SimpleX-Directory_1, #privacy SimpleX-Directory"
|
||||
cath <## "use @SimpleX-Directory <message> to send messages"
|
||||
@@ -763,9 +763,9 @@ testAnotherOwnerChangedProfile ps =
|
||||
cath <## "contact and member are merged: SimpleX-Directory_1, #privacy SimpleX-Directory"
|
||||
cath <## "use @SimpleX-Directory <message> to send messages"
|
||||
cath ##> "/gp privacy privacy Privacy and Security"
|
||||
cath <## "full name changed to: Privacy and Security"
|
||||
cath <## "description changed to: Privacy and Security"
|
||||
bob <## "cath updated group #privacy:"
|
||||
bob <## "full name changed to: Privacy and Security"
|
||||
bob <## "description changed to: Privacy and Security"
|
||||
bob <# "SimpleX-Directory> The group ID 1 (privacy) is updated by cath!"
|
||||
bob <## "It is hidden from the directory until approved."
|
||||
groupNotFound cath "privacy"
|
||||
@@ -784,9 +784,9 @@ testNotConnectedOwnerChangedProfile ps =
|
||||
registerGroup superUser bob "privacy" "Privacy"
|
||||
addCathAsOwner bob cath
|
||||
cath ##> "/gp privacy privacy Privacy and Security"
|
||||
cath <## "full name changed to: Privacy and Security"
|
||||
cath <## "description changed to: Privacy and Security"
|
||||
bob <## "cath updated group #privacy:"
|
||||
bob <## "full name changed to: Privacy and Security"
|
||||
bob <## "description changed to: Privacy and Security"
|
||||
bob <# "SimpleX-Directory> The group ID 1 (privacy) is updated by cath!"
|
||||
bob <## "It is hidden from the directory until approved."
|
||||
groupNotFound dan "privacy"
|
||||
@@ -806,13 +806,13 @@ testRegOwnerRemovedLink ps =
|
||||
bob <## "Welcome message:"
|
||||
welcomeWithLink <- getTermLine bob
|
||||
bob ##> "/set welcome #privacy Welcome!"
|
||||
bob <## "description changed to:"
|
||||
bob <## "welcome message changed to:"
|
||||
bob <## "Welcome!"
|
||||
bob <# "SimpleX-Directory> The group link for ID 1 (privacy) is removed from the welcome message."
|
||||
bob <## ""
|
||||
bob <## "The group is hidden from the directory until the group link is added and the group is re-approved."
|
||||
cath <## "bob updated group #privacy:"
|
||||
cath <## "description changed to:"
|
||||
cath <## "welcome message changed to:"
|
||||
cath <## "Welcome!"
|
||||
superUser <# "SimpleX-Directory> The group link is removed from ID 1 (privacy), de-listed."
|
||||
cath `connectVia` dsLink
|
||||
@@ -821,12 +821,12 @@ testRegOwnerRemovedLink ps =
|
||||
groupNotFound cath "privacy"
|
||||
let withChangedLink = T.unpack $ T.replace "contact#/?v=2-7&" "contact#/?v=3-7&" $ T.pack welcomeWithLink
|
||||
bob ##> ("/set welcome #privacy " <> withChangedLink)
|
||||
bob <## "description changed to:"
|
||||
bob <## "welcome message changed to:"
|
||||
bob <## withChangedLink
|
||||
bob <# "SimpleX-Directory> Thank you! The group link for ID 1 (privacy) is added to the welcome message."
|
||||
bob <## "You will be notified once the group is added to the directory - it may take up to 48 hours."
|
||||
cath <## "bob updated group #privacy:"
|
||||
cath <## "description changed to:"
|
||||
cath <## "welcome message changed to:"
|
||||
cath <## withChangedLink
|
||||
reapproveGroup 3 superUser bob
|
||||
groupFoundN 3 cath "privacy"
|
||||
@@ -846,10 +846,10 @@ testAnotherOwnerRemovedLink ps =
|
||||
bob <## "Welcome message:"
|
||||
welcomeWithLink <- getTermLine bob
|
||||
cath ##> "/set welcome #privacy Welcome!"
|
||||
cath <## "description changed to:"
|
||||
cath <## "welcome message changed to:"
|
||||
cath <## "Welcome!"
|
||||
bob <## "cath updated group #privacy:"
|
||||
bob <## "description changed to:"
|
||||
bob <## "welcome message changed to:"
|
||||
bob <## "Welcome!"
|
||||
bob <# "SimpleX-Directory> The group link for ID 1 (privacy) is removed from the welcome message by cath."
|
||||
bob <## ""
|
||||
@@ -857,10 +857,10 @@ testAnotherOwnerRemovedLink ps =
|
||||
superUser <# "SimpleX-Directory> The group link is removed from ID 1 (privacy), de-listed."
|
||||
groupNotFound cath "privacy"
|
||||
cath ##> ("/set welcome #privacy " <> welcomeWithLink)
|
||||
cath <## "description changed to:"
|
||||
cath <## "welcome message changed to:"
|
||||
cath <## welcomeWithLink
|
||||
bob <## "cath updated group #privacy:"
|
||||
bob <## "description changed to:"
|
||||
bob <## "welcome message changed to:"
|
||||
bob <## welcomeWithLink
|
||||
bob <# "SimpleX-Directory> Thank you! The group link for ID 1 (privacy) is added to the welcome message by cath."
|
||||
bob <## "You will be notified once the group is added to the directory - it may take up to 48 hours."
|
||||
@@ -881,10 +881,10 @@ testNotConnectedOwnerRemovedLink ps =
|
||||
bob <## "Welcome message:"
|
||||
welcomeWithLink <- getTermLine bob
|
||||
cath ##> "/set welcome #privacy Welcome!"
|
||||
cath <## "description changed to:"
|
||||
cath <## "welcome message changed to:"
|
||||
cath <## "Welcome!"
|
||||
bob <## "cath updated group #privacy:"
|
||||
bob <## "description changed to:"
|
||||
bob <## "welcome message changed to:"
|
||||
bob <## "Welcome!"
|
||||
bob <# "SimpleX-Directory> The group link for ID 1 (privacy) is removed from the welcome message by cath."
|
||||
bob <## ""
|
||||
@@ -892,21 +892,21 @@ testNotConnectedOwnerRemovedLink ps =
|
||||
superUser <# "SimpleX-Directory> The group link is removed from ID 1 (privacy), de-listed."
|
||||
groupNotFound dan "privacy"
|
||||
cath ##> ("/set welcome #privacy " <> welcomeWithLink)
|
||||
cath <## "description changed to:"
|
||||
cath <## "welcome message changed to:"
|
||||
cath <## welcomeWithLink
|
||||
bob <## "cath updated group #privacy:"
|
||||
bob <## "description changed to:"
|
||||
bob <## "welcome message changed to:"
|
||||
bob <## welcomeWithLink
|
||||
-- bob <# "SimpleX-Directory> The group link is added by another group member, your registration will not be processed."
|
||||
-- bob <## ""
|
||||
-- bob <## "Please update the group profile yourself."
|
||||
-- bob ##> ("/set welcome #privacy " <> welcomeWithLink <> " - welcome!")
|
||||
-- bob <## "description changed to:"
|
||||
-- bob <## "welcome message changed to:"
|
||||
-- bob <## (welcomeWithLink <> " - welcome!")
|
||||
bob <# "SimpleX-Directory> Thank you! The group link for ID 1 (privacy) is added to the welcome message by cath."
|
||||
bob <## "You will be notified once the group is added to the directory - it may take up to 48 hours."
|
||||
-- cath <## "bob updated group #privacy:"
|
||||
-- cath <## "description changed to:"
|
||||
-- cath <## "welcome message changed to:"
|
||||
-- cath <## (welcomeWithLink <> " - welcome!")
|
||||
reapproveGroup 3 superUser bob
|
||||
groupFoundN 3 dan "privacy"
|
||||
@@ -980,7 +980,7 @@ testDuplicateProhibitWhenUpdated ps =
|
||||
completeRegistration superUser bob "privacy" "Privacy" welcomeWithLink 1
|
||||
groupFound cath "privacy"
|
||||
cath ##> ("/set welcome privacy " <> welcomeWithLink')
|
||||
cath <## "description changed to:"
|
||||
cath <## "welcome message changed to:"
|
||||
cath <## welcomeWithLink'
|
||||
cath <# "SimpleX-Directory> The group privacy (Privacy) is already listed in the directory, please choose another name."
|
||||
cath ##> "/gp privacy security Security"
|
||||
@@ -1352,7 +1352,7 @@ completeRegistrationId su u n fn welcomeWithLink gId ugId = do
|
||||
updateProfileWithLink :: TestCC -> String -> String -> Int -> IO ()
|
||||
updateProfileWithLink u n welcomeWithLink ugId = do
|
||||
u ##> ("/set welcome " <> viewName n <> " " <> welcomeWithLink)
|
||||
u <## "description changed to:"
|
||||
u <## "welcome message changed to:"
|
||||
u <## welcomeWithLink
|
||||
u <# ("SimpleX-Directory> Thank you! The group link for ID " <> show ugId <> " (" <> n <> ") is added to the welcome message.")
|
||||
u <## "You will be notified once the group is added to the directory - it may take up to 48 hours."
|
||||
|
||||
+41
-21
@@ -353,7 +353,7 @@ testGroupShared alice bob cath checkMessages = do
|
||||
alice #$> ("/_get chat #1 around=" <> msgItem1 <> " count=2", chat, [(0, "connected"), (0, "connected"), (1, "hello"), (0, "hi there"), (0, "hey team")])
|
||||
alice #$> ("/_get chat #1 count=100 search=team", chat, [(0, "hey team")])
|
||||
bob @@@ [("#team", "hey team"), ("@alice", "received invitation to join group team as admin")]
|
||||
bob #$> ("/_get chat #1 count=100", chat, groupFeatures <> [(0, "connected"), (0, "added cath (Catherine)"), (0, "connected"), (0, "hello"), (1, "hi there"), (0, "hey team")])
|
||||
bob #$> ("/_get chat #1 count=100", chat, groupFeatures <> [(0, "connected"), (0, "added cath"), (0, "connected"), (0, "hello"), (1, "hi there"), (0, "hey team")])
|
||||
cath @@@ [("#team", "hey team"), ("@alice", "received invitation to join group team as admin")]
|
||||
cath #$> ("/_get chat #1 count=100", chat, groupFeatures <> [(0, "connected"), (0, "connected"), (0, "hello"), (0, "hi there"), (1, "hey team")])
|
||||
alice #$> ("/_read chat #1", id, "ok")
|
||||
@@ -586,7 +586,7 @@ testGroup2 =
|
||||
<>
|
||||
[ "#club bob> connected",
|
||||
"#club cath> connected",
|
||||
"#club bob> added dan (Daniel)",
|
||||
"#club bob> added dan",
|
||||
"#club dan> connected",
|
||||
"#club hello",
|
||||
"#club bob> hi there",
|
||||
@@ -1466,6 +1466,26 @@ testUpdateGroupProfile =
|
||||
concurrently_
|
||||
(alice <# "#my_team bob> hi")
|
||||
(cath <# "#my_team bob> hi")
|
||||
alice ##> "/gp my_team my_team My team"
|
||||
alice <## "description changed to: My team"
|
||||
concurrentlyN_
|
||||
[ do
|
||||
bob <## "alice updated group #my_team:"
|
||||
bob <## "description changed to: My team",
|
||||
do
|
||||
cath <## "alice updated group #my_team:"
|
||||
cath <## "description changed to: My team"
|
||||
]
|
||||
alice ##> "/gp my_team my_team My team updated"
|
||||
alice <## "description changed to: My team updated"
|
||||
concurrentlyN_
|
||||
[ do
|
||||
bob <## "alice updated group #my_team:"
|
||||
bob <## "description changed to: My team updated",
|
||||
do
|
||||
cath <## "alice updated group #my_team:"
|
||||
cath <## "description changed to: My team updated"
|
||||
]
|
||||
|
||||
testUpdateMemberRole :: HasCallStack => TestParams -> IO ()
|
||||
testUpdateMemberRole =
|
||||
@@ -1525,15 +1545,15 @@ testGroupDescription = testChat4 aliceProfile bobProfile cathProfile danProfile
|
||||
alice ##> "/group_profile team"
|
||||
alice <## "#team"
|
||||
groupInfo' alice
|
||||
alice ##> "/group_descr team Welcome to the team!"
|
||||
alice <## "description changed to:"
|
||||
alice ##> "/set welcome team Welcome to the team!"
|
||||
alice <## "welcome message changed to:"
|
||||
alice <## "Welcome to the team!"
|
||||
bob <## "alice updated group #team:"
|
||||
bob <## "description changed to:"
|
||||
bob <## "welcome message changed to:"
|
||||
bob <## "Welcome to the team!"
|
||||
alice ##> "/group_profile team"
|
||||
alice <## "#team"
|
||||
alice <## "description:"
|
||||
alice <## "welcome message:"
|
||||
alice <## "Welcome to the team!"
|
||||
groupInfo' alice
|
||||
connectUsers alice cath
|
||||
@@ -1845,9 +1865,9 @@ testDeleteMemberWithMessages =
|
||||
bob <## "#team: alice removed you from the group with all messages"
|
||||
bob <## "use /d #team to delete the group"
|
||||
cath <## "#team: alice removed bob from the group with all messages"
|
||||
alice #$> ("/_get chat #1 count=2", chat, [(0, "moderated [deleted by you]"), (1, "removed bob (Bob)")])
|
||||
alice #$> ("/_get chat #1 count=2", chat, [(0, "moderated [deleted by you]"), (1, "removed bob")])
|
||||
bob #$> ("/_get chat #1 count=2", chat, [(1, "moderated [deleted by alice]"), (0, "removed you")])
|
||||
cath #$> ("/_get chat #1 count=2", chat, [(0, "moderated [deleted by alice]"), (0, "removed bob (Bob)")])
|
||||
cath #$> ("/_get chat #1 count=2", chat, [(0, "moderated [deleted by alice]"), (0, "removed bob")])
|
||||
|
||||
testDeleteMemberMarkMessagesDeleted :: HasCallStack => TestParams -> IO ()
|
||||
testDeleteMemberMarkMessagesDeleted =
|
||||
@@ -1868,9 +1888,9 @@ testDeleteMemberMarkMessagesDeleted =
|
||||
bob <## "#team: alice removed you from the group with all messages"
|
||||
bob <## "use /d #team to delete the group"
|
||||
cath <## "#team: alice removed bob from the group with all messages"
|
||||
alice #$> ("/_get chat #1 count=2", chat, [(0, "hello [marked deleted by you]"), (1, "removed bob (Bob)")])
|
||||
alice #$> ("/_get chat #1 count=2", chat, [(0, "hello [marked deleted by you]"), (1, "removed bob")])
|
||||
bob #$> ("/_get chat #1 count=2", chat, [(1, "hello [marked deleted by alice]"), (0, "removed you")])
|
||||
cath #$> ("/_get chat #1 count=2", chat, [(0, "hello [marked deleted by alice]"), (0, "removed bob (Bob)")])
|
||||
cath #$> ("/_get chat #1 count=2", chat, [(0, "hello [marked deleted by alice]"), (0, "removed bob")])
|
||||
|
||||
testSendMulti :: HasCallStack => TestParams -> IO ()
|
||||
testSendMulti =
|
||||
@@ -5564,11 +5584,11 @@ testGroupHistoryWelcomeMessage =
|
||||
createGroup2 "team" alice bob
|
||||
|
||||
alice ##> "/set welcome #team welcome to team"
|
||||
alice <## "description changed to:"
|
||||
alice <## "welcome message changed to:"
|
||||
alice <## "welcome to team"
|
||||
|
||||
bob <## "alice updated group #team:"
|
||||
bob <## "description changed to:"
|
||||
bob <## "welcome message changed to:"
|
||||
bob <## "welcome to team"
|
||||
|
||||
threadDelay 1000000
|
||||
@@ -6192,10 +6212,10 @@ testBlockForAllMarkedBlocked =
|
||||
#$> ( "/_get chat #1 count=6",
|
||||
chat,
|
||||
[ (0, "1"),
|
||||
(1, "blocked bob (Bob)"),
|
||||
(1, "blocked bob"),
|
||||
(0, "2 [blocked by admin]"),
|
||||
(0, "3 [blocked by admin]"),
|
||||
(1, "unblocked bob (Bob)"),
|
||||
(1, "unblocked bob"),
|
||||
(0, "4")
|
||||
]
|
||||
)
|
||||
@@ -6203,10 +6223,10 @@ testBlockForAllMarkedBlocked =
|
||||
#$> ( "/_get chat #1 count=6",
|
||||
chat,
|
||||
[ (0, "1"),
|
||||
(0, "blocked bob (Bob)"),
|
||||
(0, "blocked bob"),
|
||||
(0, "2 [blocked by admin]"),
|
||||
(0, "3 [blocked by admin]"),
|
||||
(0, "unblocked bob (Bob)"),
|
||||
(0, "unblocked bob"),
|
||||
(0, "4")
|
||||
]
|
||||
)
|
||||
@@ -6273,10 +6293,10 @@ testBlockForAllFullDelete =
|
||||
#$> ( "/_get chat #1 count=6",
|
||||
chat,
|
||||
[ (0, "1"),
|
||||
(1, "blocked bob (Bob)"),
|
||||
(1, "blocked bob"),
|
||||
(0, "blocked [blocked by admin]"),
|
||||
(0, "blocked [blocked by admin]"),
|
||||
(1, "unblocked bob (Bob)"),
|
||||
(1, "unblocked bob"),
|
||||
(0, "4")
|
||||
]
|
||||
)
|
||||
@@ -6284,10 +6304,10 @@ testBlockForAllFullDelete =
|
||||
#$> ( "/_get chat #1 count=6",
|
||||
chat,
|
||||
[ (0, "1"),
|
||||
(0, "blocked bob (Bob)"),
|
||||
(0, "blocked bob"),
|
||||
(0, "blocked [blocked by admin]"),
|
||||
(0, "blocked [blocked by admin]"),
|
||||
(0, "unblocked bob (Bob)"),
|
||||
(0, "unblocked bob"),
|
||||
(0, "4")
|
||||
]
|
||||
)
|
||||
@@ -6380,7 +6400,7 @@ testBlockForAllBeforeJoining =
|
||||
|
||||
dan ##> "/_get chat #1 count=100"
|
||||
r <- chat <$> getTermLine dan
|
||||
r `shouldContain` [(0, "3 [blocked by admin]"), (0, "4 [blocked by admin]"), (0, "unblocked bob (Bob)"), (0, "5")]
|
||||
r `shouldContain` [(0, "3 [blocked by admin]"), (0, "4 [blocked by admin]"), (0, "unblocked bob"), (0, "5")]
|
||||
r `shouldNotContain` [(0, "1")]
|
||||
r `shouldNotContain` [(0, "1 [blocked by admin]")]
|
||||
r `shouldNotContain` [(0, "2")]
|
||||
|
||||
@@ -66,7 +66,7 @@ testUserNotes ps = withNewTestChat ps "alice" aliceProfile $ \alice -> do
|
||||
|
||||
alice ##> "/create user secret"
|
||||
alice <## "user profile: secret"
|
||||
alice <## "use /p <display name> to change it"
|
||||
alice <## "use /p <name> [<bio>] to change it"
|
||||
alice <## "(the updated profile will be sent to all your contacts)"
|
||||
|
||||
alice ##> "/tail"
|
||||
|
||||
+37
-34
@@ -156,19 +156,19 @@ testUpdateProfile =
|
||||
connectUsers bob cath
|
||||
alice ##> "/p"
|
||||
alice <## "user profile: alice (Alice)"
|
||||
alice <## "use /p <display name> to change it"
|
||||
alice <## "use /p <name> [<bio>] to change it"
|
||||
alice <## "(the updated profile will be sent to all your contacts)"
|
||||
alice ##> "/p alice"
|
||||
concurrentlyN_
|
||||
[ alice <## "user full name removed (your 2 contacts are notified)",
|
||||
bob <## "contact alice removed full name",
|
||||
cath <## "contact alice removed full name"
|
||||
[ alice <## "user bio removed (your 2 contacts are notified)",
|
||||
bob <## "contact alice removed bio",
|
||||
cath <## "contact alice removed bio"
|
||||
]
|
||||
alice ##> "/p alice Alice Jones"
|
||||
concurrentlyN_
|
||||
[ alice <## "user full name changed to Alice Jones (your 2 contacts are notified)",
|
||||
bob <## "contact alice updated full name: Alice Jones",
|
||||
cath <## "contact alice updated full name: Alice Jones"
|
||||
[ alice <## "user bio changed to Alice Jones (your 2 contacts are notified)",
|
||||
bob <## "contact alice updated bio: Alice Jones",
|
||||
cath <## "contact alice updated bio: Alice Jones"
|
||||
]
|
||||
cath ##> "/p cate"
|
||||
concurrentlyN_
|
||||
@@ -282,7 +282,7 @@ testMultiWordProfileNames =
|
||||
aliceProfile' = baseProfile {displayName = "Alice Jones"}
|
||||
bobProfile' = baseProfile {displayName = "Bob James"}
|
||||
cathProfile' = baseProfile {displayName = "Cath Johnson"}
|
||||
baseProfile = Profile {displayName = "", fullName = "", image = Nothing, contactLink = Nothing, preferences = defaultPrefs}
|
||||
baseProfile = Profile {displayName = "", fullName = "", shortDescr = Nothing, image = Nothing, contactLink = Nothing, preferences = defaultPrefs}
|
||||
|
||||
testUserContactLink :: HasCallStack => TestParams -> IO ()
|
||||
testUserContactLink =
|
||||
@@ -577,7 +577,7 @@ testDeduplicateContactRequestsProfileChange = testChat3 aliceProfile bobProfile
|
||||
alice @@@ [("@bob", "Audio/video calls: enabled")]
|
||||
|
||||
bob ##> "/p bob"
|
||||
bob <## "user full name removed (your 0 contacts are notified)"
|
||||
bob <## "user bio removed (your 0 contacts are notified)"
|
||||
bob ##> ("/c " <> cLink)
|
||||
bob <## "connection request sent!"
|
||||
alice <## "bob wants to connect to you!"
|
||||
@@ -586,7 +586,7 @@ testDeduplicateContactRequestsProfileChange = testChat3 aliceProfile bobProfile
|
||||
alice @@@ [("@bob", "Audio/video calls: enabled")]
|
||||
|
||||
bob ##> "/p bob Bob Ross"
|
||||
bob <## "user full name changed to Bob Ross (your 0 contacts are notified)"
|
||||
bob <## "user bio changed to Bob Ross (your 0 contacts are notified)"
|
||||
bob ##> ("/c " <> cLink)
|
||||
alice <#? bob
|
||||
alice @@@ [("@bob", "Audio/video calls: enabled")]
|
||||
@@ -1362,8 +1362,8 @@ testConnectIncognitoInvitationLink = testChat3 aliceProfile bobProfile cathProfi
|
||||
-- bob is not notified on profile change
|
||||
alice ##> "/p alice"
|
||||
concurrentlyN_
|
||||
[ alice <## "user full name removed (your 1 contacts are notified)",
|
||||
cath <## "contact alice removed full name"
|
||||
[ alice <## "user bio removed (your 1 contacts are notified)",
|
||||
cath <## "contact alice removed bio"
|
||||
]
|
||||
alice ?#> ("@" <> bobIncognito <> " do you see that I've changed profile?")
|
||||
bob ?<# (aliceIncognito <> "> do you see that I've changed profile?")
|
||||
@@ -1852,13 +1852,13 @@ testCantSeeGlobalPrefsUpdateIncognito = testChat3 aliceProfile bobProfile cathPr
|
||||
]
|
||||
alice <## "cath (Catherine): contact is connected"
|
||||
alice ##> "/_profile 1 {\"displayName\": \"alice\", \"fullName\": \"\", \"preferences\": {\"fullDelete\": {\"allow\": \"always\"}, \"receipts\": {\"allow\": \"yes\", \"activated\": true}}}"
|
||||
alice <## "user full name removed (your 1 contacts are notified)"
|
||||
alice <## "user bio removed (your 1 contacts are notified)"
|
||||
alice <## "updated preferences:"
|
||||
alice <## "Full deletion allowed: always"
|
||||
(alice </)
|
||||
-- bob doesn't receive profile update
|
||||
(bob </)
|
||||
cath <## "contact alice removed full name"
|
||||
cath <## "contact alice removed bio"
|
||||
cath <## "alice updated preferences for you:"
|
||||
cath <## "Full deletion: enabled for you (you allow: default (no), contact allows: always)"
|
||||
(cath </)
|
||||
@@ -2210,7 +2210,7 @@ testSetContactPrefs = testChat2 aliceProfile bobProfile $
|
||||
createDirectoryIfMissing True "./tests/tmp/bob"
|
||||
copyFile "./tests/fixtures/test.txt" "./tests/tmp/alice/test.txt"
|
||||
copyFile "./tests/fixtures/test.txt" "./tests/tmp/bob/test.txt"
|
||||
bob ##> "/_profile 1 {\"displayName\": \"bob\", \"fullName\": \"Bob\", \"preferences\": {\"voice\": {\"allow\": \"no\"}, \"receipts\": {\"allow\": \"yes\", \"activated\": true}}}"
|
||||
bob ##> "/_profile 1 {\"displayName\": \"bob\", \"fullName\": \"\", \"shortDescr\": \"Bob\", \"preferences\": {\"voice\": {\"allow\": \"no\"}, \"receipts\": {\"allow\": \"yes\", \"activated\": true}}}"
|
||||
bob <## "profile image removed"
|
||||
bob <## "updated preferences:"
|
||||
bob <## "Voice messages allowed: no"
|
||||
@@ -2270,12 +2270,12 @@ testSetContactPrefs = testChat2 aliceProfile bobProfile $
|
||||
bob #$> ("/_get chat @2 count=100", chat, startFeatures <> [(0, "Voice messages: enabled for you"), (1, "voice message (00:10)"), (0, "Voice messages: off")])
|
||||
(bob </)
|
||||
bob ##> "/_profile 1 {\"displayName\": \"bob\", \"fullName\": \"\", \"preferences\": {\"voice\": {\"allow\": \"yes\"}, \"receipts\": {\"allow\": \"yes\", \"activated\": true}}}"
|
||||
bob <## "user full name removed (your 1 contacts are notified)"
|
||||
bob <## "user bio removed (your 1 contacts are notified)"
|
||||
bob <## "updated preferences:"
|
||||
bob <## "Voice messages allowed: yes"
|
||||
bob #$> ("/_get chat @2 count=100", chat, startFeatures <> [(0, "Voice messages: enabled for you"), (1, "voice message (00:10)"), (0, "Voice messages: off"), (1, "Voice messages: enabled")])
|
||||
(bob </)
|
||||
alice <## "contact bob removed full name"
|
||||
alice <## "contact bob removed bio"
|
||||
alice <## "bob updated preferences for you:"
|
||||
alice <## "Voice messages: enabled (you allow: yes, contact allows: yes)"
|
||||
alice #$> ("/_get chat @2 count=100", chat, startFeatures <> [(1, "Voice messages: enabled for contact"), (0, "voice message (00:10)"), (1, "Voice messages: off"), (0, "updated profile"), (0, "Voice messages: enabled")])
|
||||
@@ -2596,7 +2596,7 @@ testUpdateMultipleUserPrefs = testChat3 aliceProfile bobProfile cathProfile $
|
||||
alice #> "@cath hi cath"
|
||||
cath <# "alice> hi cath"
|
||||
|
||||
alice ##> "/_profile 1 {\"displayName\": \"alice\", \"fullName\": \"Alice\", \"preferences\": {\"fullDelete\": {\"allow\": \"always\"}, \"reactions\": {\"allow\": \"no\"}, \"receipts\": {\"allow\": \"yes\", \"activated\": true}}}"
|
||||
alice ##> "/_profile 1 {\"displayName\": \"alice\", \"fullName\": \"\", \"shortDescr\": \"Alice\", \"preferences\": {\"fullDelete\": {\"allow\": \"always\"}, \"reactions\": {\"allow\": \"no\"}, \"receipts\": {\"allow\": \"yes\", \"activated\": true}}}"
|
||||
alice <## "updated preferences:"
|
||||
alice <## "Full deletion allowed: always"
|
||||
alice <## "Message reactions allowed: no"
|
||||
@@ -2786,7 +2786,7 @@ testSetUITheme =
|
||||
theme cm = T.unpack $ encodeJSON UIThemeEntityOverrides {light = Nothing, dark = Just $ UIThemeEntityOverride cm Nothing defaultUIColors}
|
||||
userInfo a name = do
|
||||
a <## ("user profile: " <> name)
|
||||
a <## "use /p <display name> to change it"
|
||||
a <## "use /p <name> [<bio>] to change it"
|
||||
a <## "(the updated profile will be sent to all your contacts)"
|
||||
contactInfo a = do
|
||||
a <## "contact ID: 2"
|
||||
@@ -2984,7 +2984,7 @@ testShortLinkInvitationPrepareContact ps@TestParams {largeLinkData} = testChatCf
|
||||
]
|
||||
alice <# "bob> hello"
|
||||
unless largeLinkData $
|
||||
bob <## "contact alice updated full name: Alice"
|
||||
bob <## "contact alice updated bio: Alice"
|
||||
concurrently_
|
||||
(bob <## "alice (Alice): contact is connected")
|
||||
(alice <## "bob (Bob): contact is connected")
|
||||
@@ -3035,9 +3035,12 @@ testShortLinkInvitationLongName = testChatCfg2 testCfg {largeLinkData = False} a
|
||||
WithTime ("@" <> longName <> " hello")
|
||||
]
|
||||
bob <# "alice> hello"
|
||||
concurrently_
|
||||
(alice <## (longName <> ": contact is connected"))
|
||||
(bob <## "alice (Alice): contact is connected")
|
||||
concurrentlyN_
|
||||
[ do
|
||||
alice <## ("contact " <> longName <> " updated bio: Bob")
|
||||
alice <## (longName <> " (Bob): contact is connected"),
|
||||
(bob <## "alice (Alice): contact is connected")
|
||||
]
|
||||
bob <##> alice
|
||||
where
|
||||
longName = "012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
|
||||
@@ -3070,7 +3073,7 @@ testShortLinkInvitationConnectRetry ps@TestParams {largeLinkData} = testChatCfgO
|
||||
]
|
||||
alice <# "bob> hello"
|
||||
unless largeLinkData $
|
||||
bob <## "contact alice updated full name: Alice"
|
||||
bob <## "contact alice updated bio: Alice"
|
||||
concurrently_
|
||||
(bob <## "alice (Alice): contact is connected")
|
||||
(alice <## "bob (Bob): contact is connected")
|
||||
@@ -3120,7 +3123,7 @@ testShortLinkAddressPrepareContact ps@TestParams {largeLinkData} = testChatCfg2
|
||||
alice ##> "/ac bob"
|
||||
alice <## "bob (Bob): accepting contact request, you can send messages to contact"
|
||||
unless largeLinkData $
|
||||
bob <## "contact alice updated full name: Alice"
|
||||
bob <## "contact alice updated bio: Alice"
|
||||
concurrently_
|
||||
(bob <## "alice (Alice): contact is connected")
|
||||
(alice <## "bob (Bob): contact is connected")
|
||||
@@ -3208,7 +3211,7 @@ testShortLinkAddressConnectRetry ps@TestParams {largeLinkData} =
|
||||
alice ##> "/ac bob"
|
||||
alice <## "bob (Bob): accepting contact request, you can send messages to contact"
|
||||
unless largeLinkData $
|
||||
bob <## "contact alice updated full name: Alice"
|
||||
bob <## "contact alice updated bio: Alice"
|
||||
concurrently_
|
||||
(bob <## "alice (Alice): contact is connected")
|
||||
(alice <## "bob (Bob): contact is connected")
|
||||
@@ -3266,7 +3269,7 @@ testShortLinkAddressConnectRetryIncognito ps@TestParams {largeLinkData} =
|
||||
alice ##> ("/ac " <> bobIncognito)
|
||||
alice <## (bobIncognito <> ": accepting contact request, you can send messages to contact")
|
||||
unless largeLinkData $
|
||||
bob <## "contact alice updated full name: Alice"
|
||||
bob <## "contact alice updated bio: Alice"
|
||||
concurrentlyN_
|
||||
[ do
|
||||
_ <- getTermLine bob
|
||||
@@ -3492,7 +3495,7 @@ testGroupShortLinkWelcome ps@TestParams {largeLinkData} = testChatCfg2 testCfg {
|
||||
alice <## "group #team is created"
|
||||
alice <## "to add members use /a team <name> or /create link #team"
|
||||
alice ##> "/set welcome #team Welcome!"
|
||||
alice <## "description changed to:"
|
||||
alice <## "welcome message changed to:"
|
||||
alice <## "Welcome!"
|
||||
alice ##> "/create link #team"
|
||||
(shortLink, fullLink) <- getGroupLinks alice "team" GRMember True
|
||||
@@ -3593,7 +3596,7 @@ testShortLinkInvitationConnectPreparedContactIncognito ps@TestParams {largeLinkD
|
||||
bobIncognito <- getTermLine bob
|
||||
bob <## "alice: connection started incognito"
|
||||
unless largeLinkData $
|
||||
bob <## "contact alice updated full name: Alice"
|
||||
bob <## "contact alice updated bio: Alice"
|
||||
_ <- getTermLine bob
|
||||
concurrentlyN_
|
||||
[ alice <## (bobIncognito <> ": contact is connected"),
|
||||
@@ -3626,7 +3629,7 @@ testShortLinkAddressConnectPreparedContactIncognito ps@TestParams {largeLinkData
|
||||
alice ##> ("/ac " <> bobIncognito)
|
||||
alice <## (bobIncognito <> ": accepting contact request, you can send messages to contact")
|
||||
unless largeLinkData $
|
||||
bob <## "contact alice updated full name: Alice"
|
||||
bob <## "contact alice updated bio: Alice"
|
||||
_ <- getTermLine bob
|
||||
concurrentlyN_
|
||||
[ alice <## (bobIncognito <> ": contact is connected"),
|
||||
@@ -3670,7 +3673,7 @@ testShortLinkChangePreparedContactUser ps@TestParams {largeLinkData} = testChatC
|
||||
]
|
||||
alice <# "robert> hello"
|
||||
unless largeLinkData $
|
||||
bob <## "contact alice updated full name: Alice"
|
||||
bob <## "contact alice updated bio: Alice"
|
||||
concurrently_
|
||||
(bob <## "alice (Alice): contact is connected")
|
||||
(alice <## "robert: contact is connected")
|
||||
@@ -3724,7 +3727,7 @@ testShortLinkChangePreparedContactUserDuplicate ps@TestParams {largeLinkData} =
|
||||
]
|
||||
alice <# "robert_1> hello"
|
||||
unless largeLinkData $
|
||||
bob <## "contact alice_1 updated full name: Alice"
|
||||
bob <## "contact alice_1 updated bio: Alice"
|
||||
concurrently_
|
||||
(bob <## "alice_1 (Alice): contact is connected")
|
||||
(alice <## "robert_1: contact is connected")
|
||||
@@ -4087,7 +4090,7 @@ testShortLinkAddressChangeAutoReply ps@TestParams {largeLinkData} = testChatCfg3
|
||||
alice <## "bob (Bob): accepting contact request..."
|
||||
alice <## "bob (Bob): you can send messages to contact"
|
||||
unless largeLinkData $
|
||||
bob <## "contact alice updated full name: Alice"
|
||||
bob <## "contact alice updated bio: Alice"
|
||||
concurrently_
|
||||
(bob <### (["alice (Alice): contact is connected"] <> [WithTime "alice> welcome!" | not largeLinkData]))
|
||||
(alice <### (["bob (Bob): contact is connected"] <> [WithTime "@bob welcome!" | not largeLinkData]))
|
||||
@@ -4109,7 +4112,7 @@ testShortLinkAddressChangeAutoReply ps@TestParams {largeLinkData} = testChatCfg3
|
||||
alice <## "cath (Catherine): accepting contact request..."
|
||||
alice <## "cath (Catherine): you can send messages to contact"
|
||||
unless largeLinkData $
|
||||
cath <## "contact alice updated full name: Alice"
|
||||
cath <## "contact alice updated bio: Alice"
|
||||
concurrently_
|
||||
(cath <## "alice (Alice): contact is connected")
|
||||
(alice <## "cath (Catherine): contact is connected")
|
||||
|
||||
+13
-10
@@ -57,25 +57,28 @@ defaultPrefs :: Maybe Preferences
|
||||
defaultPrefs = Just $ toChatPrefs defaultChatPrefs
|
||||
|
||||
aliceDesktopProfile :: Profile
|
||||
aliceDesktopProfile = Profile {displayName = "alice_desktop", fullName = "Alice Desktop", image = Nothing, contactLink = Nothing, preferences = defaultPrefs}
|
||||
aliceDesktopProfile = mkProfile "alice_desktop" "Alice Desktop" Nothing
|
||||
|
||||
aliceProfile :: Profile
|
||||
aliceProfile = Profile {displayName = "alice", fullName = "Alice", image = Nothing, contactLink = Nothing, preferences = defaultPrefs}
|
||||
aliceProfile = mkProfile "alice" "Alice" Nothing
|
||||
|
||||
bobProfile :: Profile
|
||||
bobProfile = Profile {displayName = "bob", fullName = "Bob", image = Just (ImageData "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAKHGlDQ1BJQ0MgUHJvZmlsZQAASImFVgdUVNcWve9Nb7QZeu9NehtAem/Sq6gMQ28OQxWxgAQjEFFEREARNFQFg1KjiIhiIQgoYA9IEFBisCAq6OQNJNH4//r/zDpz9ttzz7n73ffWmg0A6QCDxYqD+QCIT0hmezlYywQEBsngngEYCAIy0AC6DGYSy8rDwxUg8Xf9d7wbAxC33tHgzvrP3/9nCISFJzEBgIIRTGey2MkILkawT1oyi4tnEUxjI6IQvMLFkauYqxjQQtewwuoaHy8bBNMBwJMZDHYkAERbhJdJZUYic4hhCNZOCItOQDB3vjkzioFwxLsIXhcRl5IOAImrRzs+fivCk7QRrIL0shAcwNUW+tX8yH/tFfrPXgxG5D84Pi6F+dc9ck+HHJ7g641UMSQlQATQBHEgBaQDGcACbLAVYaIRJhx5Dv+9j77aZ4OsZIFtSEc0iARRIBnpt/9qlvfqpGSQBhjImnCEcUU+NtxnujZy4fbqVEiU/wuXdQyA9S0cDqfzC+e2F4DzyLkSB79wyi0A8KoBcL2GmcJOXePQ3C8MIAJeQAOiQArIAxXuWwMMgSmwBHbAGbgDHxAINgMmojceUZUGMkEWyAX54AA4DMpAJTgJ6sAZ0ALawQVwGVwDt8AQGAUPwQSYBi/AAngHliEIwkEUiAqJQtKQIqQO6UJ0yByyg1whLygQCoEioQQoBcqE9kD5UBFUBlVB9dBPUCd0GboBDUP3oUloDnoNfYRRMBmmwZKwEqwF02Er2AX2gTfBkXAinAHnwPvhUrgaPg23wZfhW/AoPAG/gBdRAEVCCaFkURooOsoG5Y4KQkWg2KidqDxUCaoa1YTqQvWj7qAmUPOoD2gsmoqWQWugTdGOaF80E52I3okuQJeh69Bt6D70HfQkegH9GUPBSGDUMSYYJ0wAJhKThsnFlGBqMK2Yq5hRzDTmHRaLFcIqY42wjthAbAx2O7YAewzbjO3BDmOnsIs4HE4Up44zw7njGLhkXC7uKO407hJuBDeNe48n4aXxunh7fBA+AZ+NL8E34LvxI/gZ/DKBj6BIMCG4E8II2wiFhFOELsJtwjRhmchPVCaaEX2IMcQsYimxiXiV+Ij4hkQiyZGMSZ6kaNJuUinpLOk6aZL0gSxAViPbkIPJKeT95FpyD/k++Q2FQlGiWFKCKMmU/ZR6yhXKE8p7HiqPJo8TTxjPLp5ynjaeEZ6XvAReRV4r3s28GbwlvOd4b/PO8xH4lPhs+Bh8O/nK+Tr5xvkW+an8Ovzu/PH8BfwN/Df4ZwVwAkoCdgJhAjkCJwWuCExRUVR5qg2VSd1DPUW9Sp2mYWnKNCdaDC2fdoY2SFsQFBDUF/QTTBcsF7woOCGEElISchKKEyoUahEaE/ooLClsJRwuvE+4SXhEeElEXMRSJFwkT6RZZFTko6iMqJ1orOhB0XbRx2JoMTUxT7E0seNiV8XmxWnipuJM8TzxFvEHErCEmoSXxHaJkxIDEouSUpIOkizJo5JXJOelhKQspWKkiqW6peakqdLm0tHSxdKXpJ/LCMpYycTJlMr0ySzISsg6yqbIVskOyi7LKcv5ymXLNcs9lifK0+Uj5Ivle+UXFKQV3BQyFRoVHigSFOmKUYpHFPsVl5SUlfyV9iq1K80qiyg7KWcoNyo/UqGoWKgkqlSr3FXFqtJVY1WPqQ6pwWoGalFq5Wq31WF1Q/Vo9WPqw+sw64zXJayrXjeuQdaw0kjVaNSY1BTSdNXM1mzXfKmloBWkdVCrX+uztoF2nPYp7Yc6AjrOOtk6XTqvddV0mbrlunf1KHr2erv0OvRe6avrh+sf179nQDVwM9hr0GvwydDIkG3YZDhnpGAUYlRhNE6n0T3oBfTrxhhja+NdxheMP5gYmiSbtJj8YaphGmvaYDq7Xnl9+PpT66fM5MwYZlVmE+Yy5iHmJ8wnLGQtGBbVFk8t5S3DLGssZ6xUrWKsTlu9tNa2Zlu3Wi/ZmNjssOmxRdk62ObZDtoJ2Pnaldk9sZezj7RvtF9wMHDY7tDjiHF0cTzoOO4k6cR0qndacDZy3uHc50J28XYpc3nqqubKdu1yg92c3Q65PdqguCFhQ7s7cHdyP+T+2EPZI9HjZ0+sp4dnueczLx2vTK9+b6r3Fu8G73c+1j6FPg99VXxTfHv9eP2C/er9lvxt/Yv8JwK0AnYE3AoUC4wO7AjCBfkF1QQtbrTbeHjjdLBBcG7w2CblTembbmwW2xy3+eIW3i2MLedCMCH+IQ0hKwx3RjVjMdQptCJ0gWnDPMJ8EWYZVhw2F24WXhQ+E2EWURQxG2kWeShyLsoiqiRqPtomuiz6VYxjTGXMUqx7bG0sJ84/rjkeHx8S35kgkBCb0LdVamv61mGWOiuXNZFokng4cYHtwq5JgpI2JXUk05A/0oEUlZTvUiZTzVPLU9+n+aWdS+dPT0gf2Ka2bd+2mQz7jB+3o7czt/dmymZmZU7usNpRtRPaGbqzd5f8rpxd07sddtdlEbNis37J1s4uyn67x39PV45kzu6cqe8cvmvM5cll547vNd1b+T36++jvB/fp7Tu673NeWN7NfO38kvyVAmbBzR90fij9gbM/Yv9goWHh8QPYAwkHxg5aHKwr4i/KKJo65HaorVimOK/47eEth2+U6JdUHiEeSTkyUepa2nFU4eiBoytlUWWj5dblzRUSFfsqlo6FHRs5bnm8qVKyMr/y44noE/eqHKraqpWqS05iT6aefHbK71T/j/Qf62vEavJrPtUm1E7UedX11RvV1zdINBQ2wo0pjXOng08PnbE909Gk0VTVLNScfxacTTn7/KeQn8ZaXFp6z9HPNZ1XPF/RSm3Na4PatrUttEe1T3QEdgx3Onf2dpl2tf6s+XPtBdkL5RcFLxZ2E7tzujmXMi4t9rB65i9HXp7q3dL78ErAlbt9nn2DV12uXr9mf+1Kv1X/petm1y/cMLnReZN+s/2W4a22AYOB1l8MfmkdNBxsu210u2PIeKhreP1w94jFyOU7tneu3XW6e2t0w+jwmO/YvfHg8Yl7Yfdm78fdf/Ug9cHyw92PMI/yHvM9Lnki8aT6V9VfmycMJy5O2k4OPPV++nCKOfXit6TfVqZznlGelcxIz9TP6s5emLOfG3q+8fn0C9aL5fnc3/l/r3ip8vL8H5Z/DCwELEy/Yr/ivC54I/qm9q3+295Fj8Un7+LfLS/lvRd9X/eB/qH/o//HmeW0FdxK6SfVT12fXT4/4sRzOCwGm7FqBVBIwhERALyuBYASCAB1CPEPG9f8119+BvrK2fyNwVndL5jhvubRVsMQgCakeCFp04OsQ1LJEgAe5NodqT6WANbT+yf/iqQIPd21PXgaAcDJcjivtwJAQHLFgcNZ9uBwPlUgYhHf1z37f7V9g9e8ITewiP88wfWIYET6HPg21nzjV2fybQVcxfrg2/onng/F50lD/ccAAAA4ZVhJZk1NACoAAAAIAAGHaQAEAAAAAQAAABoAAAAAAAKgAgAEAAAAAQAAABigAwAEAAAAAQAAABgAAAAAwf1XlwAAAaNJREFUSA3FlT1LA0EQQBN/gYUYRTksJZVgEbCR/D+7QMr8ABtttBBCsLGzsLG2sxaxED/ie4d77u0dyaE5HHjczn7MzO7M7nU6/yXz+bwLhzCCjTQO+rZhDH3opuNLdRYN4RHe4RIKJ7R34Ro+4AEGSw2mE1iUwT18gpI74WvkGlccu4XNdH0jnYU7cAUacidn37qR23cOxc4aGU0nYUAn7iSWEHkz46w0ocdQu1X6B/AMQZ5o7KfBqNOfwRH8JB7FajGhnmcpKvQe3MEbvILiDm5gPXaCHnZr4vvFGMoEKudKn8YvQIOOe+YzCPop7dwJ3zRfJ7GDuso4YJGRa0yZgg4tUaNXdGrbuZWKKxzYYEJc2xp9AUUjGt8KC2jvgYadF8+10vJyDnNLXwbdiWUZi0fUK01Eoc+AZhCLZVzK4Vq6sDUdz+0dEcbbTTIOJmAyTVhx/WmvrExbv2jtPhWLKodjCtefZiEeZeVZWWSndgwj6fVf3XON8Qwq15++uoqrfYVrow6dGBpCq79ME291jaB0/Q2CPncyht/99MNO/vr9AqW/CGi8sJqbAAAAAElFTkSuQmCC"), contactLink = Nothing, preferences = defaultPrefs}
|
||||
bobProfile = mkProfile "bob" "Bob" $ Just $ ImageData "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAKHGlDQ1BJQ0MgUHJvZmlsZQAASImFVgdUVNcWve9Nb7QZeu9NehtAem/Sq6gMQ28OQxWxgAQjEFFEREARNFQFg1KjiIhiIQgoYA9IEFBisCAq6OQNJNH4//r/zDpz9ttzz7n73ffWmg0A6QCDxYqD+QCIT0hmezlYywQEBsngngEYCAIy0AC6DGYSy8rDwxUg8Xf9d7wbAxC33tHgzvrP3/9nCISFJzEBgIIRTGey2MkILkawT1oyi4tnEUxjI6IQvMLFkauYqxjQQtewwuoaHy8bBNMBwJMZDHYkAERbhJdJZUYic4hhCNZOCItOQDB3vjkzioFwxLsIXhcRl5IOAImrRzs+fivCk7QRrIL0shAcwNUW+tX8yH/tFfrPXgxG5D84Pi6F+dc9ck+HHJ7g641UMSQlQATQBHEgBaQDGcACbLAVYaIRJhx5Dv+9j77aZ4OsZIFtSEc0iARRIBnpt/9qlvfqpGSQBhjImnCEcUU+NtxnujZy4fbqVEiU/wuXdQyA9S0cDqfzC+e2F4DzyLkSB79wyi0A8KoBcL2GmcJOXePQ3C8MIAJeQAOiQArIAxXuWwMMgSmwBHbAGbgDHxAINgMmojceUZUGMkEWyAX54AA4DMpAJTgJ6sAZ0ALawQVwGVwDt8AQGAUPwQSYBi/AAngHliEIwkEUiAqJQtKQIqQO6UJ0yByyg1whLygQCoEioQQoBcqE9kD5UBFUBlVB9dBPUCd0GboBDUP3oUloDnoNfYRRMBmmwZKwEqwF02Er2AX2gTfBkXAinAHnwPvhUrgaPg23wZfhW/AoPAG/gBdRAEVCCaFkURooOsoG5Y4KQkWg2KidqDxUCaoa1YTqQvWj7qAmUPOoD2gsmoqWQWugTdGOaF80E52I3okuQJeh69Bt6D70HfQkegH9GUPBSGDUMSYYJ0wAJhKThsnFlGBqMK2Yq5hRzDTmHRaLFcIqY42wjthAbAx2O7YAewzbjO3BDmOnsIs4HE4Up44zw7njGLhkXC7uKO407hJuBDeNe48n4aXxunh7fBA+AZ+NL8E34LvxI/gZ/DKBj6BIMCG4E8II2wiFhFOELsJtwjRhmchPVCaaEX2IMcQsYimxiXiV+Ij4hkQiyZGMSZ6kaNJuUinpLOk6aZL0gSxAViPbkIPJKeT95FpyD/k++Q2FQlGiWFKCKMmU/ZR6yhXKE8p7HiqPJo8TTxjPLp5ynjaeEZ6XvAReRV4r3s28GbwlvOd4b/PO8xH4lPhs+Bh8O/nK+Tr5xvkW+an8Ovzu/PH8BfwN/Df4ZwVwAkoCdgJhAjkCJwWuCExRUVR5qg2VSd1DPUW9Sp2mYWnKNCdaDC2fdoY2SFsQFBDUF/QTTBcsF7woOCGEElISchKKEyoUahEaE/ooLClsJRwuvE+4SXhEeElEXMRSJFwkT6RZZFTko6iMqJ1orOhB0XbRx2JoMTUxT7E0seNiV8XmxWnipuJM8TzxFvEHErCEmoSXxHaJkxIDEouSUpIOkizJo5JXJOelhKQspWKkiqW6peakqdLm0tHSxdKXpJ/LCMpYycTJlMr0ySzISsg6yqbIVskOyi7LKcv5ymXLNcs9lifK0+Uj5Ivle+UXFKQV3BQyFRoVHigSFOmKUYpHFPsVl5SUlfyV9iq1K80qiyg7KWcoNyo/UqGoWKgkqlSr3FXFqtJVY1WPqQ6pwWoGalFq5Wq31WF1Q/Vo9WPqw+sw64zXJayrXjeuQdaw0kjVaNSY1BTSdNXM1mzXfKmloBWkdVCrX+uztoF2nPYp7Yc6AjrOOtk6XTqvddV0mbrlunf1KHr2erv0OvRe6avrh+sf179nQDVwM9hr0GvwydDIkG3YZDhnpGAUYlRhNE6n0T3oBfTrxhhja+NdxheMP5gYmiSbtJj8YaphGmvaYDq7Xnl9+PpT66fM5MwYZlVmE+Yy5iHmJ8wnLGQtGBbVFk8t5S3DLGssZ6xUrWKsTlu9tNa2Zlu3Wi/ZmNjssOmxRdk62ObZDtoJ2Pnaldk9sZezj7RvtF9wMHDY7tDjiHF0cTzoOO4k6cR0qndacDZy3uHc50J28XYpc3nqqubKdu1yg92c3Q65PdqguCFhQ7s7cHdyP+T+2EPZI9HjZ0+sp4dnueczLx2vTK9+b6r3Fu8G73c+1j6FPg99VXxTfHv9eP2C/er9lvxt/Yv8JwK0AnYE3AoUC4wO7AjCBfkF1QQtbrTbeHjjdLBBcG7w2CblTembbmwW2xy3+eIW3i2MLedCMCH+IQ0hKwx3RjVjMdQptCJ0gWnDPMJ8EWYZVhw2F24WXhQ+E2EWURQxG2kWeShyLsoiqiRqPtomuiz6VYxjTGXMUqx7bG0sJ84/rjkeHx8S35kgkBCb0LdVamv61mGWOiuXNZFokng4cYHtwq5JgpI2JXUk05A/0oEUlZTvUiZTzVPLU9+n+aWdS+dPT0gf2Ka2bd+2mQz7jB+3o7czt/dmymZmZU7usNpRtRPaGbqzd5f8rpxd07sddtdlEbNis37J1s4uyn67x39PV45kzu6cqe8cvmvM5cll547vNd1b+T36++jvB/fp7Tu673NeWN7NfO38kvyVAmbBzR90fij9gbM/Yv9goWHh8QPYAwkHxg5aHKwr4i/KKJo65HaorVimOK/47eEth2+U6JdUHiEeSTkyUepa2nFU4eiBoytlUWWj5dblzRUSFfsqlo6FHRs5bnm8qVKyMr/y44noE/eqHKraqpWqS05iT6aefHbK71T/j/Qf62vEavJrPtUm1E7UedX11RvV1zdINBQ2wo0pjXOng08PnbE909Gk0VTVLNScfxacTTn7/KeQn8ZaXFp6z9HPNZ1XPF/RSm3Na4PatrUttEe1T3QEdgx3Onf2dpl2tf6s+XPtBdkL5RcFLxZ2E7tzujmXMi4t9rB65i9HXp7q3dL78ErAlbt9nn2DV12uXr9mf+1Kv1X/petm1y/cMLnReZN+s/2W4a22AYOB1l8MfmkdNBxsu210u2PIeKhreP1w94jFyOU7tneu3XW6e2t0w+jwmO/YvfHg8Yl7Yfdm78fdf/Ug9cHyw92PMI/yHvM9Lnki8aT6V9VfmycMJy5O2k4OPPV++nCKOfXit6TfVqZznlGelcxIz9TP6s5emLOfG3q+8fn0C9aL5fnc3/l/r3ip8vL8H5Z/DCwELEy/Yr/ivC54I/qm9q3+295Fj8Un7+LfLS/lvRd9X/eB/qH/o//HmeW0FdxK6SfVT12fXT4/4sRzOCwGm7FqBVBIwhERALyuBYASCAB1CPEPG9f8119+BvrK2fyNwVndL5jhvubRVsMQgCakeCFp04OsQ1LJEgAe5NodqT6WANbT+yf/iqQIPd21PXgaAcDJcjivtwJAQHLFgcNZ9uBwPlUgYhHf1z37f7V9g9e8ITewiP88wfWIYET6HPg21nzjV2fybQVcxfrg2/onng/F50lD/ccAAAA4ZVhJZk1NACoAAAAIAAGHaQAEAAAAAQAAABoAAAAAAAKgAgAEAAAAAQAAABigAwAEAAAAAQAAABgAAAAAwf1XlwAAAaNJREFUSA3FlT1LA0EQQBN/gYUYRTksJZVgEbCR/D+7QMr8ABtttBBCsLGzsLG2sxaxED/ie4d77u0dyaE5HHjczn7MzO7M7nU6/yXz+bwLhzCCjTQO+rZhDH3opuNLdRYN4RHe4RIKJ7R34Ro+4AEGSw2mE1iUwT18gpI74WvkGlccu4XNdH0jnYU7cAUacidn37qR23cOxc4aGU0nYUAn7iSWEHkz46w0ocdQu1X6B/AMQZ5o7KfBqNOfwRH8JB7FajGhnmcpKvQe3MEbvILiDm5gPXaCHnZr4vvFGMoEKudKn8YvQIOOe+YzCPop7dwJ3zRfJ7GDuso4YJGRa0yZgg4tUaNXdGrbuZWKKxzYYEJc2xp9AUUjGt8KC2jvgYadF8+10vJyDnNLXwbdiWUZi0fUK01Eoc+AZhCLZVzK4Vq6sDUdz+0dEcbbTTIOJmAyTVhx/WmvrExbv2jtPhWLKodjCtefZiEeZeVZWWSndgwj6fVf3XON8Qwq15++uoqrfYVrow6dGBpCq79ME291jaB0/Q2CPncyht/99MNO/vr9AqW/CGi8sJqbAAAAAElFTkSuQmCC"
|
||||
|
||||
cathProfile :: Profile
|
||||
cathProfile = Profile {displayName = "cath", fullName = "Catherine", image = Nothing, contactLink = Nothing, preferences = defaultPrefs}
|
||||
cathProfile = mkProfile "cath" "Catherine" Nothing
|
||||
|
||||
danProfile :: Profile
|
||||
danProfile = Profile {displayName = "dan", fullName = "Daniel", image = Nothing, contactLink = Nothing, preferences = defaultPrefs}
|
||||
danProfile = mkProfile "dan" "Daniel" Nothing
|
||||
|
||||
eveProfile :: Profile
|
||||
eveProfile = Profile {displayName = "eve", fullName = "Eve", image = Nothing, contactLink = Nothing, preferences = defaultPrefs}
|
||||
eveProfile = mkProfile "eve" "Eve" Nothing
|
||||
|
||||
businessProfile :: Profile
|
||||
businessProfile = Profile {displayName = "biz", fullName = "Biz Inc", image = Nothing, contactLink = Nothing, preferences = defaultPrefs}
|
||||
businessProfile = mkProfile "biz" "Biz Inc" Nothing
|
||||
|
||||
mkProfile :: T.Text -> T.Text -> Maybe ImageData -> Profile
|
||||
mkProfile displayName descr image = Profile {displayName, fullName = "", shortDescr = Just descr, image, contactLink = Nothing, preferences = defaultPrefs}
|
||||
|
||||
it :: HasCallStack => String -> (TestParams -> Expectation) -> SpecWith (Arg (TestParams -> Expectation))
|
||||
it name test =
|
||||
@@ -685,7 +688,7 @@ lastItemId cc = do
|
||||
showActiveUser :: HasCallStack => TestCC -> String -> Expectation
|
||||
showActiveUser cc name = do
|
||||
cc <## ("user profile: " <> name)
|
||||
cc <## "use /p <display name> to change it"
|
||||
cc <## "use /p <name> [<bio>] to change it"
|
||||
cc <## "(the updated profile will be sent to all your contacts)"
|
||||
|
||||
connectUsersNoShortLink :: HasCallStack => TestCC -> TestCC -> IO ()
|
||||
@@ -710,8 +713,8 @@ connectUsers_ cc1 cc2 noShortLink = do
|
||||
|
||||
showName :: TestCC -> IO String
|
||||
showName (TestCC ChatController {currentUser} _ _ _ _ _) = do
|
||||
Just User {localDisplayName, profile = LocalProfile {fullName}} <- readTVarIO currentUser
|
||||
pure . T.unpack $ localDisplayName <> optionalFullName localDisplayName fullName
|
||||
Just User {localDisplayName, profile = LocalProfile {fullName, shortDescr}} <- readTVarIO currentUser
|
||||
pure . T.unpack $ localDisplayName <> optionalFullName localDisplayName fullName shortDescr
|
||||
|
||||
createGroup2 :: HasCallStack => String -> TestCC -> TestCC -> IO ()
|
||||
createGroup2 gName cc1 cc2 = createGroup2' gName cc1 (cc2, GRAdmin) True
|
||||
|
||||
@@ -17,10 +17,10 @@ activeUserExistsTagged :: LB.ByteString
|
||||
activeUserExistsTagged = "{\"error\":{\"type\":\"error\",\"errorType\":{\"type\":\"userExists\",\"contactName\":\"alice\"}}}"
|
||||
|
||||
activeUserSwift :: LB.ByteString
|
||||
activeUserSwift = "{\"result\":{\"_owsf\":true,\"activeUser\":{\"user\":{\"userId\":1,\"agentUserId\":\"1\",\"userContactId\":1,\"localDisplayName\":\"alice\",\"profile\":{\"profileId\":1,\"displayName\":\"alice\",\"fullName\":\"Alice\",\"localAlias\":\"\"},\"fullPreferences\":{\"timedMessages\":{\"allow\":\"yes\"},\"fullDelete\":{\"allow\":\"no\"},\"reactions\":{\"allow\":\"yes\"},\"voice\":{\"allow\":\"yes\"},\"calls\":{\"allow\":\"yes\"}},\"activeUser\":true,\"activeOrder\":1,\"showNtfs\":true,\"sendRcptsContacts\":true,\"sendRcptsSmallGroups\":true}}}}"
|
||||
activeUserSwift = "{\"result\":{\"_owsf\":true,\"activeUser\":{\"user\":{\"userId\":1,\"agentUserId\":\"1\",\"userContactId\":1,\"localDisplayName\":\"alice\",\"profile\":{\"profileId\":1,\"displayName\":\"alice\",\"fullName\":\"\",\"shortDescr\":\"Alice\",\"localAlias\":\"\"},\"fullPreferences\":{\"timedMessages\":{\"allow\":\"yes\"},\"fullDelete\":{\"allow\":\"no\"},\"reactions\":{\"allow\":\"yes\"},\"voice\":{\"allow\":\"yes\"},\"calls\":{\"allow\":\"yes\"}},\"activeUser\":true,\"activeOrder\":1,\"showNtfs\":true,\"sendRcptsContacts\":true,\"sendRcptsSmallGroups\":true}}}}"
|
||||
|
||||
activeUserTagged :: LB.ByteString
|
||||
activeUserTagged = "{\"result\":{\"type\":\"activeUser\",\"user\":{\"userId\":1,\"agentUserId\":\"1\",\"userContactId\":1,\"localDisplayName\":\"alice\",\"profile\":{\"profileId\":1,\"displayName\":\"alice\",\"fullName\":\"Alice\",\"localAlias\":\"\"},\"fullPreferences\":{\"timedMessages\":{\"allow\":\"yes\"},\"fullDelete\":{\"allow\":\"no\"},\"reactions\":{\"allow\":\"yes\"},\"voice\":{\"allow\":\"yes\"},\"calls\":{\"allow\":\"yes\"}},\"activeUser\":true,\"activeOrder\":1,\"showNtfs\":true,\"sendRcptsContacts\":true,\"sendRcptsSmallGroups\":true}}}"
|
||||
activeUserTagged = "{\"result\":{\"type\":\"activeUser\",\"user\":{\"userId\":1,\"agentUserId\":\"1\",\"userContactId\":1,\"localDisplayName\":\"alice\",\"profile\":{\"profileId\":1,\"displayName\":\"alice\",\"fullName\":\"\",\"shortDescr\":\"Alice\",\"localAlias\":\"\"},\"fullPreferences\":{\"timedMessages\":{\"allow\":\"yes\"},\"fullDelete\":{\"allow\":\"no\"},\"reactions\":{\"allow\":\"yes\"},\"voice\":{\"allow\":\"yes\"},\"calls\":{\"allow\":\"yes\"}},\"activeUser\":true,\"activeOrder\":1,\"showNtfs\":true,\"sendRcptsContacts\":true,\"sendRcptsSmallGroups\":true}}}"
|
||||
|
||||
chatStartedSwift :: LB.ByteString
|
||||
chatStartedSwift = "{\"result\":{\"_owsf\":true,\"chatStarted\":{}}}"
|
||||
@@ -35,7 +35,7 @@ networkStatusesTagged :: LB.ByteString
|
||||
networkStatusesTagged = "{\"result\":{\"type\":\"networkStatuses\",\"user_\":" <> userJSON <> ",\"networkStatuses\":[]}}"
|
||||
|
||||
userJSON :: LB.ByteString
|
||||
userJSON = "{\"userId\":1,\"agentUserId\":\"1\",\"userContactId\":1,\"localDisplayName\":\"alice\",\"profile\":{\"profileId\":1,\"displayName\":\"alice\",\"fullName\":\"Alice\",\"localAlias\":\"\"},\"fullPreferences\":{\"timedMessages\":{\"allow\":\"yes\"},\"fullDelete\":{\"allow\":\"no\"},\"reactions\":{\"allow\":\"yes\"},\"voice\":{\"allow\":\"yes\"},\"calls\":{\"allow\":\"yes\"}},\"activeUser\":true,\"activeOrder\":1,\"showNtfs\":true,\"sendRcptsContacts\":true,\"sendRcptsSmallGroups\":true}"
|
||||
userJSON = "{\"userId\":1,\"agentUserId\":\"1\",\"userContactId\":1,\"localDisplayName\":\"alice\",\"profile\":{\"profileId\":1,\"displayName\":\"alice\",\"fullName\":\"\",\"shortDescr\":\"Alice\",\"localAlias\":\"\"},\"fullPreferences\":{\"timedMessages\":{\"allow\":\"yes\"},\"fullDelete\":{\"allow\":\"no\"},\"reactions\":{\"allow\":\"yes\"},\"voice\":{\"allow\":\"yes\"},\"calls\":{\"allow\":\"yes\"}},\"activeUser\":true,\"activeOrder\":1,\"showNtfs\":true,\"sendRcptsContacts\":true,\"sendRcptsSmallGroups\":true}"
|
||||
|
||||
memberSubSummarySwift :: LB.ByteString
|
||||
memberSubSummarySwift = "{\"result\":{\"_owsf\":true,\"memberSubSummary\":{\"user\":" <> userJSON <> ",\"memberSubscriptions\":[]}}}"
|
||||
|
||||
@@ -104,10 +104,10 @@ testGroupPreferences :: Maybe GroupPreferences
|
||||
testGroupPreferences = Just GroupPreferences {timedMessages = Nothing, directMessages = Nothing, reactions = Just ReactionsGroupPreference {enable = FEOn}, voice = Just VoiceGroupPreference {enable = FEOn, role = Nothing}, files = Nothing, fullDelete = Nothing, simplexLinks = Nothing, history = Nothing, reports = Nothing}
|
||||
|
||||
testProfile :: Profile
|
||||
testProfile = Profile {displayName = "alice", fullName = "Alice", image = Just (ImageData "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII="), contactLink = Nothing, preferences = testChatPreferences}
|
||||
testProfile = Profile {displayName = "alice", fullName = "Alice", shortDescr = Nothing, image = Just (ImageData "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII="), contactLink = Nothing, preferences = testChatPreferences}
|
||||
|
||||
testGroupProfile :: GroupProfile
|
||||
testGroupProfile = GroupProfile {displayName = "team", fullName = "Team", description = Nothing, image = Nothing, groupPreferences = testGroupPreferences, memberAdmission = Nothing}
|
||||
testGroupProfile = GroupProfile {displayName = "team", fullName = "Team", description = Nothing, shortDescr = Nothing, image = Nothing, groupPreferences = testGroupPreferences, memberAdmission = Nothing}
|
||||
|
||||
decodeChatMessageTest :: Spec
|
||||
decodeChatMessageTest = describe "Chat message encoding/decoding" $ do
|
||||
@@ -223,7 +223,7 @@ decodeChatMessageTest = describe "Chat message encoding/decoding" $ do
|
||||
#==# XInfo testProfile
|
||||
it "x.info with empty full name" $
|
||||
"{\"v\":\"1\",\"event\":\"x.info\",\"params\":{\"profile\":{\"fullName\":\"\",\"displayName\":\"alice\",\"preferences\":{\"reactions\":{\"allow\":\"yes\"},\"voice\":{\"allow\":\"yes\"}}}}}"
|
||||
#==# XInfo Profile {displayName = "alice", fullName = "", image = Nothing, contactLink = Nothing, preferences = testChatPreferences}
|
||||
#==# XInfo Profile {displayName = "alice", fullName = "", shortDescr = Nothing, image = Nothing, contactLink = Nothing, preferences = testChatPreferences}
|
||||
it "x.contact with xContactId" $
|
||||
"{\"v\":\"1\",\"event\":\"x.contact\",\"params\":{\"contactReqId\":\"AQIDBA==\",\"profile\":{\"fullName\":\"Alice\",\"displayName\":\"alice\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\",\"preferences\":{\"reactions\":{\"allow\":\"yes\"},\"voice\":{\"allow\":\"yes\"}}}}}"
|
||||
#==# XContact testProfile (Just $ XContactId "\1\2\3\4") Nothing Nothing
|
||||
|
||||
@@ -448,7 +448,7 @@ multipleProfilesTest = testChat4 aliceProfile aliceDesktopProfile bobProfile cat
|
||||
|
||||
desktop ##> "/create user desk_bottom"
|
||||
desktop <## "user profile: desk_bottom"
|
||||
desktop <## "use /p <display name> to change it"
|
||||
desktop <## "use /p <name> [<bio>] to change it"
|
||||
desktop <## "(the updated profile will be sent to all your contacts)"
|
||||
desktop ##> "/users"
|
||||
desktop <## "alice_desktop (Alice Desktop)"
|
||||
@@ -461,7 +461,7 @@ multipleProfilesTest = testChat4 aliceProfile aliceDesktopProfile bobProfile cat
|
||||
|
||||
desktop ##> "/create user alt_alice"
|
||||
desktop <## "user profile: alt_alice"
|
||||
desktop <## "use /p <display name> to change it"
|
||||
desktop <## "use /p <name> [<bio>] to change it"
|
||||
desktop <## "(the updated profile will be sent to all your contacts)"
|
||||
|
||||
desktop ##> "/users"
|
||||
@@ -470,7 +470,7 @@ multipleProfilesTest = testChat4 aliceProfile aliceDesktopProfile bobProfile cat
|
||||
|
||||
desktop ##> "/user"
|
||||
desktop <## "user profile: alt_alice"
|
||||
desktop <## "use /p <display name> to change it"
|
||||
desktop <## "use /p <name> [<bio>] to change it"
|
||||
desktop <## "(the updated profile will be sent to all your contacts)"
|
||||
|
||||
bob #> "@alice hi"
|
||||
@@ -483,7 +483,7 @@ multipleProfilesTest = testChat4 aliceProfile aliceDesktopProfile bobProfile cat
|
||||
desktop <## "Using local profile"
|
||||
desktop ##> "/user"
|
||||
desktop <## "user profile: desk_bottom"
|
||||
desktop <## "use /p <display name> to change it"
|
||||
desktop <## "use /p <name> [<bio>] to change it"
|
||||
desktop <## "(the updated profile will be sent to all your contacts)"
|
||||
|
||||
bob #> "@alice hey"
|
||||
|
||||
Reference in New Issue
Block a user