diff --git a/client/react-native/android/app/src/main/java/chat/berty/core/notification/NotificationNative.java b/client/react-native/android/app/src/main/java/chat/berty/core/notification/NotificationNative.java
index fa11088bc0..dbfb16f00d 100644
--- a/client/react-native/android/app/src/main/java/chat/berty/core/notification/NotificationNative.java
+++ b/client/react-native/android/app/src/main/java/chat/berty/core/notification/NotificationNative.java
@@ -19,7 +19,7 @@ public class NotificationNative implements NativeNotificationDriver {
public static int PERMISSION_CODE = 200;
private Logger logger = new Logger("chat.berty.io");
- private static final String CHANNEL_ID = "berty-chat-android-notification-id";
+ private static final String CHANNEL_ID = "berty-chat-wandroid-notification-id";
private static final String CHANNEL_NAME = "berty.chat.android.core.notification.name";
private static final String CHANNEL_DESCRIPTION = "berty.chat.android.core.notification.description";
diff --git a/client/react-native/common/components/Library/ContactIdentityActions/ActionsUnknown.js b/client/react-native/common/components/Library/ContactIdentityActions/ActionsUnknown.js
new file mode 100644
index 0000000000..4ac63a08bf
--- /dev/null
+++ b/client/react-native/common/components/Library/ContactIdentityActions/ActionsUnknown.js
@@ -0,0 +1,47 @@
+import React from 'react'
+import { colors } from '../../../constants'
+import ActionList from './ActionList'
+import RelayContext from '../../../relay/RelayContext'
+import { withNamespaces } from 'react-i18next'
+
+const ActionsUnknown = ({ data, inModal, t }) => (
+
+ {({ mutations }) => (
+
+ {
+ const contact = Object.keys(data)
+ .filter(key => key.substring(0, 2) !== '__')
+ .reduce(
+ (acc, key) => ({
+ ...acc,
+ [key]: data[key],
+ }),
+ {}
+ )
+ return mutations.contactRequest({
+ contactId: contact.id,
+ contactOverrideDisplayName:
+ contact.overrideDisplayName || contact.displayName || '',
+ introText: '',
+ })
+ }}
+ successMessage={t('contacts.request-action-feedback')}
+ />
+ mutations.contactRemove({ id: data.id })}
+ successMessage={t('contacts.cancel-request-action-feedback')}
+ />
+
+ )}
+
+)
+
+export default withNamespaces()(ActionsUnknown)
diff --git a/client/react-native/common/components/Screens/Chats/Detail.js b/client/react-native/common/components/Screens/Chats/Detail.js
index f01e6c0a15..74898c508a 100644
--- a/client/react-native/common/components/Screens/Chats/Detail.js
+++ b/client/react-native/common/components/Screens/Chats/Detail.js
@@ -70,9 +70,9 @@ class Message extends React.Component {
data: { seenAt },
} = this.props
if (seenAt !== nextProps.data.seenAt) {
- return false
+ return true
}
- return true
+ return false
}
render () {
@@ -87,9 +87,8 @@ class Message extends React.Component {
const isMyself = contact && contact.status === 42
const isOneToOne =
conversation.kind === enums.BertyEntityConversationInputKind.OneToOne
-
- // TODO: implement message seen
- if (this.props.data.seenAt === null) {
+ // TODO: implement message seeni
+ if (new Date(this.props.data.seenAt).getTime() === 0) {
this.messageSeen()
}
return (
@@ -147,9 +146,7 @@ class Message extends React.Component {
{dateFns.fuzzyTimeOrFull(new Date(data.createdAt))}{' '}
{isMyself ? (
0 ? 'check-circle' : 'circle'
- }
+ name={utils.isReadByOthers(data) ? 'check-circle' : 'circle'}
size={10}
/>
) : null}{' '}
diff --git a/client/react-native/common/components/Screens/Chats/List.js b/client/react-native/common/components/Screens/Chats/List.js
index 4a22f4d66a..ff961667e3 100644
--- a/client/react-native/common/components/Screens/Chats/List.js
+++ b/client/react-native/common/components/Screens/Chats/List.js
@@ -139,8 +139,7 @@ const ItemBase = fragments.Conversation(
const { data, navigation, t } = this.props
const { connected, unread } = this.state
- const isRead = utils.isRead(data)
-
+ const isRead = utils.isReadByMe(data)
// fix when contact request is send after conversation invite
if (
data.members.length === 2 &&
diff --git a/client/react-native/common/components/Screens/Contacts/List/Item.js b/client/react-native/common/components/Screens/Contacts/List/Item.js
index 49d749a80e..742db29ced 100644
--- a/client/react-native/common/components/Screens/Contacts/List/Item.js
+++ b/client/react-native/common/components/Screens/Contacts/List/Item.js
@@ -5,60 +5,64 @@ import { borderBottom, marginLeft, padding } from '../../../../styles'
import { colors } from '../../../../constants'
import { showContact } from '../../../../helpers/contacts'
import { withNavigation } from 'react-navigation'
+import ActionsUnknown from '../../../Library/ContactIdentityActions/ActionsUnknown'
import ActionsReceived from '../../../Library/ContactIdentityActions/ActionsReceived'
import ActionsSent from '../../../Library/ContactIdentityActions/ActionsSent'
import { withNamespaces } from 'react-i18next'
-const Item = fragments.Contact(class Item extends PureComponent {
- async showDetails () {
- const { data, context, navigation } = this.props
+const Item = fragments.Contact(
+ class Item extends PureComponent {
+ async showDetails () {
+ const { data, context, navigation } = this.props
- return showContact({ data, context, navigation })
- }
+ return showContact({ data, context, navigation })
+ }
- render () {
- const { data, ignoreMyself, t } = this.props
- const { overrideDisplayName, displayName, status } = data
+ render () {
+ const { data, ignoreMyself, t } = this.props
+ const { overrideDisplayName, displayName, status } = data
- if (
- ignoreMyself &&
+ if (
+ ignoreMyself &&
status === enums.BertyEntityContactInputStatus.Myself
- ) {
- return null
- }
+ ) {
+ return null
+ }
- return (
- this.showDetails()}
- >
-
-
-
-
- {overrideDisplayName || displayName}
-
-
- {t(`contacts.statuses.${
- enums.ValueBertyEntityContactInputStatus[status]
- }`)}
-
-
+ return (
+ this.showDetails()}
+ >
+
+
+
+
+ {overrideDisplayName || displayName}
+
+
+ {t(
+ `contacts.statuses.${
+ enums.ValueBertyEntityContactInputStatus[status]
+ }`
+ )}
+
+
+
+ {status === enums.BertyEntityContactInputStatus.Unknown && (
+
+ )}
+ {status === enums.BertyEntityContactInputStatus.RequestedMe && (
+
+ )}
+ {status === enums.BertyEntityContactInputStatus.IsRequested && (
+
+ )}
- {status === enums.BertyEntityContactInputStatus.RequestedMe && (
-
- )}
- {status === enums.BertyEntityContactInputStatus.IsRequested && (
-
- )}
-
- )
+ )
+ }
}
-})
+)
export default withNavigation(withNamespaces()(Item))
diff --git a/client/react-native/common/graphql/fragments/Conversation.js b/client/react-native/common/graphql/fragments/Conversation.js
index 76b827a5ae..12b6c921be 100644
--- a/client/react-native/common/graphql/fragments/Conversation.js
+++ b/client/react-native/common/graphql/fragments/Conversation.js
@@ -9,6 +9,7 @@ export default component =>
createdAt
updatedAt
readAt
+ wroteAt
title
topic
infos
@@ -18,6 +19,7 @@ export default component =>
createdAt
updatedAt
readAt
+ wroteAt
status
contact {
id
diff --git a/client/react-native/common/graphql/queries/Conversation.js b/client/react-native/common/graphql/queries/Conversation.js
index e05fce0f49..a085a108b8 100644
--- a/client/react-native/common/graphql/queries/Conversation.js
+++ b/client/react-native/common/graphql/queries/Conversation.js
@@ -9,6 +9,7 @@ const query = graphql`
$createdAt: GoogleProtobufTimestampInput
$updatedAt: GoogleProtobufTimestampInput
$readAt: GoogleProtobufTimestampInput
+ $wroteAt: GoogleProtobufTimestampInput
$title: String!
$topic: String!
$infos: String!
@@ -19,6 +20,7 @@ const query = graphql`
createdAt: $createdAt
updatedAt: $updatedAt
readAt: $readAt
+ wroteAt: $wroteAt
title: $title
topic: $topic
infos: $infos
@@ -29,6 +31,7 @@ const query = graphql`
createdAt
updatedAt
readAt
+ wroteAt
title
topic
infos
@@ -36,6 +39,7 @@ const query = graphql`
id
createdAt
updatedAt
+ wroteAt
status
contact {
id
diff --git a/client/react-native/common/i18n/en/messages.json b/client/react-native/common/i18n/en/messages.json
index 990a5f0c1d..959ff7e8bf 100644
--- a/client/react-native/common/i18n/en/messages.json
+++ b/client/react-native/common/i18n/en/messages.json
@@ -169,6 +169,8 @@
"decline-action-feedback": "Contact request has been declined",
"resend-action": "Resend",
"resend-action-feedback": "Contact request has been sent again",
+ "request-action": "Request",
+ "request-action-feedback": "Contact request has been sent",
"cancel-request-action": "Remove",
"cancel-request-action-feedback": "Contact invitation has been removed",
"block-confirm-question": "Are you sure you want to block this contact?",
diff --git a/client/react-native/common/i18n/fr/messages.json b/client/react-native/common/i18n/fr/messages.json
index 60363b42ec..63372697c5 100644
--- a/client/react-native/common/i18n/fr/messages.json
+++ b/client/react-native/common/i18n/fr/messages.json
@@ -169,6 +169,8 @@
"decline-action-feedback": "L'invitation a été refusée",
"resend-action": "Renvoyer",
"resend-action-feedback": "L'invitation a été envoyée à nouveau",
+ "request-action": "Ajouter",
+ "request-action-feedback": "L'invitation a été envoyée",
"cancel-request-action": "Annuler",
"cancel-request-action-feedback": "L'invitation a été annulée",
"block-confirm-question": "Êtes vous sûr de vouloir bloquer ce contact ?",
diff --git a/client/react-native/common/schema.graphql b/client/react-native/common/schema.graphql
index 69f0eac413..ec0a9a8bc2 100644
--- a/client/react-native/common/schema.graphql
+++ b/client/react-native/common/schema.graphql
@@ -298,6 +298,7 @@ type BertyEntityConversation implements Node {
createdAt: GoogleProtobufTimestamp
updatedAt: GoogleProtobufTimestamp
readAt: GoogleProtobufTimestamp
+ wroteAt: GoogleProtobufTimestamp
title: String!
topic: String!
infos: String!
@@ -310,6 +311,7 @@ type BertyEntityConversationMember implements Node {
createdAt: GoogleProtobufTimestamp
updatedAt: GoogleProtobufTimestamp
readAt: GoogleProtobufTimestamp
+ wroteAt: GoogleProtobufTimestamp
status: Enum
contact: BertyEntityContact
conversationId: ID!
@@ -794,27 +796,29 @@ input BertyEntityContactInput {
overrideDisplayName: String!
overrideDisplayStatus: String!
}
+input BertyEntityConversationMemberInput {
+ id: ID!
+ createdAt: GoogleProtobufTimestampInput
+ updatedAt: GoogleProtobufTimestampInput
+ readAt: GoogleProtobufTimestampInput
+ wroteAt: GoogleProtobufTimestampInput
+ status: Enum
+ contact: BertyEntityContactInput
+ conversationId: ID!
+ contactId: ID!
+}
input BertyEntityConversationInput {
id: ID!
createdAt: GoogleProtobufTimestampInput
updatedAt: GoogleProtobufTimestampInput
readAt: GoogleProtobufTimestampInput
+ wroteAt: GoogleProtobufTimestampInput
title: String!
topic: String!
infos: String!
kind: Enum
members: [BertyEntityConversationMemberInput]
}
-input BertyEntityConversationMemberInput {
- id: ID!
- createdAt: GoogleProtobufTimestampInput
- updatedAt: GoogleProtobufTimestampInput
- readAt: GoogleProtobufTimestampInput
- status: Enum
- contact: BertyEntityContactInput
- conversationId: ID!
- contactId: ID!
-}
input BertyEntityMessageInput {
text: String!
}
@@ -882,6 +886,7 @@ type Query {
createdAt: GoogleProtobufTimestampInput
updatedAt: GoogleProtobufTimestampInput
readAt: GoogleProtobufTimestampInput
+ wroteAt: GoogleProtobufTimestampInput
title: String!
topic: String!
infos: String!
@@ -893,6 +898,7 @@ type Query {
createdAt: GoogleProtobufTimestampInput
updatedAt: GoogleProtobufTimestampInput
readAt: GoogleProtobufTimestampInput
+ wroteAt: GoogleProtobufTimestampInput
status: Enum
contact: BertyEntityContactInput
conversationId: ID!
@@ -1010,6 +1016,7 @@ type Mutation {
createdAt: GoogleProtobufTimestampInput
updatedAt: GoogleProtobufTimestampInput
readAt: GoogleProtobufTimestampInput
+ wroteAt: GoogleProtobufTimestampInput
title: String!
topic: String!
infos: String!
diff --git a/client/react-native/common/utils/conversation.js b/client/react-native/common/utils/conversation.js
index 20232709a5..34f9b8ec6d 100644
--- a/client/react-native/common/utils/conversation.js
+++ b/client/react-native/common/utils/conversation.js
@@ -28,12 +28,26 @@ export const getTitle = ({ title, members }) =>
export const getRelayID = id => btoa(`conversation:${id}`)
export const getCoreID = id => atob(id).match(/:(.*)$/)[1]
-export const isRead = ({ members }) => {
+export const isReadByMe = ({ wroteAt, members }) => {
const myself = members.find(
- _ => _.contact.status === BertyEntityContactInputStatus.Myself
+ _ => _.contact && _.contact.status === BertyEntityContactInputStatus.Myself
)
if (myself == null) {
return true
}
- return new Date(myself.readAt).getTime() > 0
+ return new Date(myself.readAt).getTime() >= new Date(wroteAt).getTime()
}
+
+export const isMessageReadByMe = ({ members }, { createdAt }) => {
+ const myself = members.find(
+ _ => _.contact && _.contact.status === BertyEntityContactInputStatus.Myself
+ )
+ if (myself == null) {
+ return true
+ }
+ return new Date(myself.readAt).getTime() >= new Date(createdAt).getTime()
+}
+
+export const isReadByOthers = message =>
+ message.dispatches &&
+ message.dispatches.some(_ => new Date(_.ackedAt).getTime() > 0)
diff --git a/core/api/node/graphql/gqlgen.gen.yml b/core/api/node/graphql/gqlgen.gen.yml
index 78311b5915..065c6c1e54 100644
--- a/core/api/node/graphql/gqlgen.gen.yml
+++ b/core/api/node/graphql/gqlgen.gen.yml
@@ -874,6 +874,7 @@ models:
createdAt:
updatedAt:
readAt:
+ wroteAt:
title:
topic:
infos:
@@ -887,6 +888,7 @@ models:
createdAt:
updatedAt:
readAt:
+ wroteAt:
title:
topic:
infos:
@@ -900,6 +902,7 @@ models:
createdAt:
updatedAt:
readAt:
+ wroteAt:
title:
topic:
infos:
@@ -914,6 +917,7 @@ models:
createdAt:
updatedAt:
readAt:
+ wroteAt:
status:
contact:
conversationId:
@@ -928,6 +932,7 @@ models:
createdAt:
updatedAt:
readAt:
+ wroteAt:
status:
contact:
conversationId:
@@ -942,6 +947,7 @@ models:
createdAt:
updatedAt:
readAt:
+ wroteAt:
status:
contact:
conversationId:
diff --git a/core/api/node/graphql/graph/generated/generated.gen.go b/core/api/node/graphql/graph/generated/generated.gen.go
index b595d8e584..f252ca7ed6 100644
--- a/core/api/node/graphql/graph/generated/generated.gen.go
+++ b/core/api/node/graphql/graph/generated/generated.gen.go
@@ -118,6 +118,7 @@ type ComplexityRoot struct {
CreatedAt func(childComplexity int) int
UpdatedAt func(childComplexity int) int
ReadAt func(childComplexity int) int
+ WroteAt func(childComplexity int) int
Title func(childComplexity int) int
Topic func(childComplexity int) int
Infos func(childComplexity int) int
@@ -134,6 +135,7 @@ type ComplexityRoot struct {
CreatedAt func(childComplexity int) int
UpdatedAt func(childComplexity int) int
ReadAt func(childComplexity int) int
+ WroteAt func(childComplexity int) int
Status func(childComplexity int) int
Contact func(childComplexity int) int
ConversationId func(childComplexity int) int
@@ -753,7 +755,7 @@ type ComplexityRoot struct {
ContactRemove func(childComplexity int, id string, createdAt *time.Time, updatedAt *time.Time, sigchain []byte, status *int32, devices []*entity.Device, displayName string, displayStatus string, overrideDisplayName string, overrideDisplayStatus string) int
ContactUpdate func(childComplexity int, id string, createdAt *time.Time, updatedAt *time.Time, sigchain []byte, status *int32, devices []*entity.Device, displayName string, displayStatus string, overrideDisplayName string, overrideDisplayStatus string) int
ConversationCreate func(childComplexity int, contacts []*entity.Contact, title string, topic string, kind *int32) int
- ConversationUpdate func(childComplexity int, id string, createdAt *time.Time, updatedAt *time.Time, readAt *time.Time, title string, topic string, infos string, kind *int32, members []*entity.ConversationMember) int
+ ConversationUpdate func(childComplexity int, id string, createdAt *time.Time, updatedAt *time.Time, readAt *time.Time, wroteAt *time.Time, title string, topic string, infos string, kind *int32, members []*entity.ConversationMember) int
ConversationInvite func(childComplexity int, conversation *entity.Conversation, contacts []*entity.Contact) int
ConversationExclude func(childComplexity int, conversation *entity.Conversation, contacts []*entity.Contact) int
ConversationAddMessage func(childComplexity int, conversation *entity.Conversation, message *entity.Message) int
@@ -781,8 +783,8 @@ type ComplexityRoot struct {
Contact func(childComplexity int, filter *entity.Contact) int
ContactCheckPublicKey func(childComplexity int, filter *entity.Contact) int
ConversationList func(childComplexity int, filter *entity.Conversation, orderBy string, orderDesc bool, first *int32, after *string, last *int32, before *string) int
- Conversation func(childComplexity int, id string, createdAt *time.Time, updatedAt *time.Time, readAt *time.Time, title string, topic string, infos string, kind *int32, members []*entity.ConversationMember) int
- ConversationMember func(childComplexity int, id string, createdAt *time.Time, updatedAt *time.Time, readAt *time.Time, status *int32, contact *entity.Contact, conversationId string, contactId string) int
+ Conversation func(childComplexity int, id string, createdAt *time.Time, updatedAt *time.Time, readAt *time.Time, wroteAt *time.Time, title string, topic string, infos string, kind *int32, members []*entity.ConversationMember) int
+ ConversationMember func(childComplexity int, id string, createdAt *time.Time, updatedAt *time.Time, readAt *time.Time, wroteAt *time.Time, status *int32, contact *entity.Contact, conversationId string, contactId string) int
ConversationLastEvent func(childComplexity int, id string) int
DevicePushConfigList func(childComplexity int, T bool) int
DeviceInfos func(childComplexity int, T bool) int
@@ -864,7 +866,7 @@ type MutationResolver interface {
ContactRemove(ctx context.Context, id string, createdAt *time.Time, updatedAt *time.Time, sigchain []byte, status *int32, devices []*entity.Device, displayName string, displayStatus string, overrideDisplayName string, overrideDisplayStatus string) (*entity.Contact, error)
ContactUpdate(ctx context.Context, id string, createdAt *time.Time, updatedAt *time.Time, sigchain []byte, status *int32, devices []*entity.Device, displayName string, displayStatus string, overrideDisplayName string, overrideDisplayStatus string) (*entity.Contact, error)
ConversationCreate(ctx context.Context, contacts []*entity.Contact, title string, topic string, kind *int32) (*entity.Conversation, error)
- ConversationUpdate(ctx context.Context, id string, createdAt *time.Time, updatedAt *time.Time, readAt *time.Time, title string, topic string, infos string, kind *int32, members []*entity.ConversationMember) (*entity.Conversation, error)
+ ConversationUpdate(ctx context.Context, id string, createdAt *time.Time, updatedAt *time.Time, readAt *time.Time, wroteAt *time.Time, title string, topic string, infos string, kind *int32, members []*entity.ConversationMember) (*entity.Conversation, error)
ConversationInvite(ctx context.Context, conversation *entity.Conversation, contacts []*entity.Contact) (*entity.Conversation, error)
ConversationExclude(ctx context.Context, conversation *entity.Conversation, contacts []*entity.Contact) (*entity.Conversation, error)
ConversationAddMessage(ctx context.Context, conversation *entity.Conversation, message *entity.Message) (*entity.Event, error)
@@ -891,8 +893,8 @@ type QueryResolver interface {
Contact(ctx context.Context, filter *entity.Contact) (*entity.Contact, error)
ContactCheckPublicKey(ctx context.Context, filter *entity.Contact) (*node.Bool, error)
ConversationList(ctx context.Context, filter *entity.Conversation, orderBy string, orderDesc bool, first *int32, after *string, last *int32, before *string) (*node.ConversationListConnection, error)
- Conversation(ctx context.Context, id string, createdAt *time.Time, updatedAt *time.Time, readAt *time.Time, title string, topic string, infos string, kind *int32, members []*entity.ConversationMember) (*entity.Conversation, error)
- ConversationMember(ctx context.Context, id string, createdAt *time.Time, updatedAt *time.Time, readAt *time.Time, status *int32, contact *entity.Contact, conversationId string, contactId string) (*entity.ConversationMember, error)
+ Conversation(ctx context.Context, id string, createdAt *time.Time, updatedAt *time.Time, readAt *time.Time, wroteAt *time.Time, title string, topic string, infos string, kind *int32, members []*entity.ConversationMember) (*entity.Conversation, error)
+ ConversationMember(ctx context.Context, id string, createdAt *time.Time, updatedAt *time.Time, readAt *time.Time, wroteAt *time.Time, status *int32, contact *entity.Contact, conversationId string, contactId string) (*entity.ConversationMember, error)
ConversationLastEvent(ctx context.Context, id string) (*entity.Event, error)
DevicePushConfigList(ctx context.Context, T bool) (*node.DevicePushConfigListOutput, error)
DeviceInfos(ctx context.Context, T bool) (*deviceinfo.DeviceInfos, error)
@@ -1529,48 +1531,62 @@ func field_Mutation_ConversationUpdate_args(rawArgs map[string]interface{}) (map
}
}
args["readAt"] = arg3
- var arg4 string
- if tmp, ok := rawArgs["title"]; ok {
+ var arg4 *time.Time
+ if tmp, ok := rawArgs["wroteAt"]; ok {
var err error
- arg4, err = models.UnmarshalString(tmp)
+ var ptr1 time.Time
+ if tmp != nil {
+ ptr1, err = models.UnmarshalTime(tmp)
+ arg4 = &ptr1
+ }
+
if err != nil {
return nil, err
}
}
- args["title"] = arg4
+ args["wroteAt"] = arg4
var arg5 string
- if tmp, ok := rawArgs["topic"]; ok {
+ if tmp, ok := rawArgs["title"]; ok {
var err error
arg5, err = models.UnmarshalString(tmp)
if err != nil {
return nil, err
}
}
- args["topic"] = arg5
+ args["title"] = arg5
var arg6 string
- if tmp, ok := rawArgs["infos"]; ok {
+ if tmp, ok := rawArgs["topic"]; ok {
var err error
arg6, err = models.UnmarshalString(tmp)
if err != nil {
return nil, err
}
}
- args["infos"] = arg6
- var arg7 *int32
+ args["topic"] = arg6
+ var arg7 string
+ if tmp, ok := rawArgs["infos"]; ok {
+ var err error
+ arg7, err = models.UnmarshalString(tmp)
+ if err != nil {
+ return nil, err
+ }
+ }
+ args["infos"] = arg7
+ var arg8 *int32
if tmp, ok := rawArgs["kind"]; ok {
var err error
var ptr1 int32
if tmp != nil {
ptr1, err = models.UnmarshalEnum(tmp)
- arg7 = &ptr1
+ arg8 = &ptr1
}
if err != nil {
return nil, err
}
}
- args["kind"] = arg7
- var arg8 []*entity.ConversationMember
+ args["kind"] = arg8
+ var arg9 []*entity.ConversationMember
if tmp, ok := rawArgs["members"]; ok {
var err error
var rawIf1 []interface{}
@@ -1581,19 +1597,19 @@ func field_Mutation_ConversationUpdate_args(rawArgs map[string]interface{}) (map
rawIf1 = []interface{}{tmp}
}
}
- arg8 = make([]*entity.ConversationMember, len(rawIf1))
+ arg9 = make([]*entity.ConversationMember, len(rawIf1))
for idx1 := range rawIf1 {
var ptr2 entity.ConversationMember
if rawIf1[idx1] != nil {
ptr2, err = UnmarshalBertyEntityConversationMemberInput(rawIf1[idx1])
- arg8[idx1] = &ptr2
+ arg9[idx1] = &ptr2
}
}
if err != nil {
return nil, err
}
}
- args["members"] = arg8
+ args["members"] = arg9
return args, nil
}
@@ -2589,48 +2605,62 @@ func field_Query_Conversation_args(rawArgs map[string]interface{}) (map[string]i
}
}
args["readAt"] = arg3
- var arg4 string
- if tmp, ok := rawArgs["title"]; ok {
+ var arg4 *time.Time
+ if tmp, ok := rawArgs["wroteAt"]; ok {
var err error
- arg4, err = models.UnmarshalString(tmp)
+ var ptr1 time.Time
+ if tmp != nil {
+ ptr1, err = models.UnmarshalTime(tmp)
+ arg4 = &ptr1
+ }
+
if err != nil {
return nil, err
}
}
- args["title"] = arg4
+ args["wroteAt"] = arg4
var arg5 string
- if tmp, ok := rawArgs["topic"]; ok {
+ if tmp, ok := rawArgs["title"]; ok {
var err error
arg5, err = models.UnmarshalString(tmp)
if err != nil {
return nil, err
}
}
- args["topic"] = arg5
+ args["title"] = arg5
var arg6 string
- if tmp, ok := rawArgs["infos"]; ok {
+ if tmp, ok := rawArgs["topic"]; ok {
var err error
arg6, err = models.UnmarshalString(tmp)
if err != nil {
return nil, err
}
}
- args["infos"] = arg6
- var arg7 *int32
+ args["topic"] = arg6
+ var arg7 string
+ if tmp, ok := rawArgs["infos"]; ok {
+ var err error
+ arg7, err = models.UnmarshalString(tmp)
+ if err != nil {
+ return nil, err
+ }
+ }
+ args["infos"] = arg7
+ var arg8 *int32
if tmp, ok := rawArgs["kind"]; ok {
var err error
var ptr1 int32
if tmp != nil {
ptr1, err = models.UnmarshalEnum(tmp)
- arg7 = &ptr1
+ arg8 = &ptr1
}
if err != nil {
return nil, err
}
}
- args["kind"] = arg7
- var arg8 []*entity.ConversationMember
+ args["kind"] = arg8
+ var arg9 []*entity.ConversationMember
if tmp, ok := rawArgs["members"]; ok {
var err error
var rawIf1 []interface{}
@@ -2641,19 +2671,19 @@ func field_Query_Conversation_args(rawArgs map[string]interface{}) (map[string]i
rawIf1 = []interface{}{tmp}
}
}
- arg8 = make([]*entity.ConversationMember, len(rawIf1))
+ arg9 = make([]*entity.ConversationMember, len(rawIf1))
for idx1 := range rawIf1 {
var ptr2 entity.ConversationMember
if rawIf1[idx1] != nil {
ptr2, err = UnmarshalBertyEntityConversationMemberInput(rawIf1[idx1])
- arg8[idx1] = &ptr2
+ arg9[idx1] = &ptr2
}
}
if err != nil {
return nil, err
}
}
- args["members"] = arg8
+ args["members"] = arg9
return args, nil
}
@@ -2711,52 +2741,66 @@ func field_Query_ConversationMember_args(rawArgs map[string]interface{}) (map[st
}
}
args["readAt"] = arg3
- var arg4 *int32
+ var arg4 *time.Time
+ if tmp, ok := rawArgs["wroteAt"]; ok {
+ var err error
+ var ptr1 time.Time
+ if tmp != nil {
+ ptr1, err = models.UnmarshalTime(tmp)
+ arg4 = &ptr1
+ }
+
+ if err != nil {
+ return nil, err
+ }
+ }
+ args["wroteAt"] = arg4
+ var arg5 *int32
if tmp, ok := rawArgs["status"]; ok {
var err error
var ptr1 int32
if tmp != nil {
ptr1, err = models.UnmarshalEnum(tmp)
- arg4 = &ptr1
+ arg5 = &ptr1
}
if err != nil {
return nil, err
}
}
- args["status"] = arg4
- var arg5 *entity.Contact
+ args["status"] = arg5
+ var arg6 *entity.Contact
if tmp, ok := rawArgs["contact"]; ok {
var err error
var ptr1 entity.Contact
if tmp != nil {
ptr1, err = UnmarshalBertyEntityContactInput(tmp)
- arg5 = &ptr1
+ arg6 = &ptr1
}
if err != nil {
return nil, err
}
}
- args["contact"] = arg5
- var arg6 string
+ args["contact"] = arg6
+ var arg7 string
if tmp, ok := rawArgs["conversationId"]; ok {
var err error
- arg6, err = models.UnmarshalID(tmp)
+ arg7, err = models.UnmarshalID(tmp)
if err != nil {
return nil, err
}
}
- args["conversationId"] = arg6
- var arg7 string
+ args["conversationId"] = arg7
+ var arg8 string
if tmp, ok := rawArgs["contactId"]; ok {
var err error
- arg7, err = models.UnmarshalID(tmp)
+ arg8, err = models.UnmarshalID(tmp)
if err != nil {
return nil, err
}
}
- args["contactId"] = arg7
+ args["contactId"] = arg8
return args, nil
}
@@ -3513,6 +3557,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.BertyEntityConversation.ReadAt(childComplexity), true
+ case "BertyEntityConversation.wroteAt":
+ if e.complexity.BertyEntityConversation.WroteAt == nil {
+ break
+ }
+
+ return e.complexity.BertyEntityConversation.WroteAt(childComplexity), true
+
case "BertyEntityConversation.title":
if e.complexity.BertyEntityConversation.Title == nil {
break
@@ -3583,6 +3634,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.BertyEntityConversationMember.ReadAt(childComplexity), true
+ case "BertyEntityConversationMember.wroteAt":
+ if e.complexity.BertyEntityConversationMember.WroteAt == nil {
+ break
+ }
+
+ return e.complexity.BertyEntityConversationMember.WroteAt(childComplexity), true
+
case "BertyEntityConversationMember.status":
if e.complexity.BertyEntityConversationMember.Status == nil {
break
@@ -5903,7 +5961,7 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return 0, false
}
- return e.complexity.Mutation.ConversationUpdate(childComplexity, args["id"].(string), args["createdAt"].(*time.Time), args["updatedAt"].(*time.Time), args["readAt"].(*time.Time), args["title"].(string), args["topic"].(string), args["infos"].(string), args["kind"].(*int32), args["members"].([]*entity.ConversationMember)), true
+ return e.complexity.Mutation.ConversationUpdate(childComplexity, args["id"].(string), args["createdAt"].(*time.Time), args["updatedAt"].(*time.Time), args["readAt"].(*time.Time), args["wroteAt"].(*time.Time), args["title"].(string), args["topic"].(string), args["infos"].(string), args["kind"].(*int32), args["members"].([]*entity.ConversationMember)), true
case "Mutation.ConversationInvite":
if e.complexity.Mutation.ConversationInvite == nil {
@@ -6203,7 +6261,7 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return 0, false
}
- return e.complexity.Query.Conversation(childComplexity, args["id"].(string), args["createdAt"].(*time.Time), args["updatedAt"].(*time.Time), args["readAt"].(*time.Time), args["title"].(string), args["topic"].(string), args["infos"].(string), args["kind"].(*int32), args["members"].([]*entity.ConversationMember)), true
+ return e.complexity.Query.Conversation(childComplexity, args["id"].(string), args["createdAt"].(*time.Time), args["updatedAt"].(*time.Time), args["readAt"].(*time.Time), args["wroteAt"].(*time.Time), args["title"].(string), args["topic"].(string), args["infos"].(string), args["kind"].(*int32), args["members"].([]*entity.ConversationMember)), true
case "Query.ConversationMember":
if e.complexity.Query.ConversationMember == nil {
@@ -6215,7 +6273,7 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return 0, false
}
- return e.complexity.Query.ConversationMember(childComplexity, args["id"].(string), args["createdAt"].(*time.Time), args["updatedAt"].(*time.Time), args["readAt"].(*time.Time), args["status"].(*int32), args["contact"].(*entity.Contact), args["conversationId"].(string), args["contactId"].(string)), true
+ return e.complexity.Query.ConversationMember(childComplexity, args["id"].(string), args["createdAt"].(*time.Time), args["updatedAt"].(*time.Time), args["readAt"].(*time.Time), args["wroteAt"].(*time.Time), args["status"].(*int32), args["contact"].(*entity.Contact), args["conversationId"].(string), args["contactId"].(string)), true
case "Query.ConversationLastEvent":
if e.complexity.Query.ConversationLastEvent == nil {
@@ -7593,6 +7651,8 @@ func (ec *executionContext) _BertyEntityConversation(ctx context.Context, sel as
out.Values[i] = ec._BertyEntityConversation_updatedAt(ctx, field, obj)
case "readAt":
out.Values[i] = ec._BertyEntityConversation_readAt(ctx, field, obj)
+ case "wroteAt":
+ out.Values[i] = ec._BertyEntityConversation_wroteAt(ctx, field, obj)
case "title":
out.Values[i] = ec._BertyEntityConversation_title(ctx, field, obj)
if out.Values[i] == graphql.Null {
@@ -7706,6 +7766,26 @@ func (ec *executionContext) _BertyEntityConversation_readAt(ctx context.Context,
return models.MarshalTime(res)
}
+// nolint: vetshadow
+func (ec *executionContext) _BertyEntityConversation_wroteAt(ctx context.Context, field graphql.CollectedField, obj *entity.Conversation) graphql.Marshaler {
+ rctx := &graphql.ResolverContext{
+ Object: "BertyEntityConversation",
+ Args: nil,
+ Field: field,
+ }
+ ctx = graphql.WithResolverContext(ctx, rctx)
+ resTmp := ec.FieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.WroteAt, nil
+ })
+ if resTmp == nil {
+ return graphql.Null
+ }
+ res := resTmp.(time.Time)
+ rctx.Result = res
+ return models.MarshalTime(res)
+}
+
// nolint: vetshadow
func (ec *executionContext) _BertyEntityConversation_title(ctx context.Context, field graphql.CollectedField, obj *entity.Conversation) graphql.Marshaler {
rctx := &graphql.ResolverContext{
@@ -7934,6 +8014,8 @@ func (ec *executionContext) _BertyEntityConversationMember(ctx context.Context,
out.Values[i] = ec._BertyEntityConversationMember_updatedAt(ctx, field, obj)
case "readAt":
out.Values[i] = ec._BertyEntityConversationMember_readAt(ctx, field, obj)
+ case "wroteAt":
+ out.Values[i] = ec._BertyEntityConversationMember_wroteAt(ctx, field, obj)
case "status":
out.Values[i] = ec._BertyEntityConversationMember_status(ctx, field, obj)
case "contact":
@@ -8050,6 +8132,26 @@ func (ec *executionContext) _BertyEntityConversationMember_readAt(ctx context.Co
return models.MarshalTime(res)
}
+// nolint: vetshadow
+func (ec *executionContext) _BertyEntityConversationMember_wroteAt(ctx context.Context, field graphql.CollectedField, obj *entity.ConversationMember) graphql.Marshaler {
+ rctx := &graphql.ResolverContext{
+ Object: "BertyEntityConversationMember",
+ Args: nil,
+ Field: field,
+ }
+ ctx = graphql.WithResolverContext(ctx, rctx)
+ resTmp := ec.FieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.WroteAt, nil
+ })
+ if resTmp == nil {
+ return graphql.Null
+ }
+ res := resTmp.(time.Time)
+ rctx.Result = res
+ return models.MarshalTime(res)
+}
+
// nolint: vetshadow
func (ec *executionContext) _BertyEntityConversationMember_status(ctx context.Context, field graphql.CollectedField, obj *entity.ConversationMember) graphql.Marshaler {
rctx := &graphql.ResolverContext{
@@ -21179,7 +21281,7 @@ func (ec *executionContext) _Mutation_ConversationUpdate(ctx context.Context, fi
ctx = graphql.WithResolverContext(ctx, rctx)
resTmp := ec.FieldMiddleware(ctx, nil, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
- return ec.resolvers.Mutation().ConversationUpdate(rctx, args["id"].(string), args["createdAt"].(*time.Time), args["updatedAt"].(*time.Time), args["readAt"].(*time.Time), args["title"].(string), args["topic"].(string), args["infos"].(string), args["kind"].(*int32), args["members"].([]*entity.ConversationMember))
+ return ec.resolvers.Mutation().ConversationUpdate(rctx, args["id"].(string), args["createdAt"].(*time.Time), args["updatedAt"].(*time.Time), args["readAt"].(*time.Time), args["wroteAt"].(*time.Time), args["title"].(string), args["topic"].(string), args["infos"].(string), args["kind"].(*int32), args["members"].([]*entity.ConversationMember))
})
if resTmp == nil {
return graphql.Null
@@ -22178,7 +22280,7 @@ func (ec *executionContext) _Query_Conversation(ctx context.Context, field graph
ctx = graphql.WithResolverContext(ctx, rctx)
resTmp := ec.FieldMiddleware(ctx, nil, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
- return ec.resolvers.Query().Conversation(rctx, args["id"].(string), args["createdAt"].(*time.Time), args["updatedAt"].(*time.Time), args["readAt"].(*time.Time), args["title"].(string), args["topic"].(string), args["infos"].(string), args["kind"].(*int32), args["members"].([]*entity.ConversationMember))
+ return ec.resolvers.Query().Conversation(rctx, args["id"].(string), args["createdAt"].(*time.Time), args["updatedAt"].(*time.Time), args["readAt"].(*time.Time), args["wroteAt"].(*time.Time), args["title"].(string), args["topic"].(string), args["infos"].(string), args["kind"].(*int32), args["members"].([]*entity.ConversationMember))
})
if resTmp == nil {
return graphql.Null
@@ -22209,7 +22311,7 @@ func (ec *executionContext) _Query_ConversationMember(ctx context.Context, field
ctx = graphql.WithResolverContext(ctx, rctx)
resTmp := ec.FieldMiddleware(ctx, nil, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
- return ec.resolvers.Query().ConversationMember(rctx, args["id"].(string), args["createdAt"].(*time.Time), args["updatedAt"].(*time.Time), args["readAt"].(*time.Time), args["status"].(*int32), args["contact"].(*entity.Contact), args["conversationId"].(string), args["contactId"].(string))
+ return ec.resolvers.Query().ConversationMember(rctx, args["id"].(string), args["createdAt"].(*time.Time), args["updatedAt"].(*time.Time), args["readAt"].(*time.Time), args["wroteAt"].(*time.Time), args["status"].(*int32), args["contact"].(*entity.Contact), args["conversationId"].(string), args["contactId"].(string))
})
if resTmp == nil {
return graphql.Null
@@ -24493,6 +24595,12 @@ func UnmarshalBertyEntityConversationInput(v interface{}) (entity.Conversation,
if err != nil {
return it, err
}
+ case "wroteAt":
+ var err error
+ it.WroteAt, err = models.UnmarshalTime(v)
+ if err != nil {
+ return it, err
+ }
case "title":
var err error
it.Title, err = models.UnmarshalString(v)
@@ -24577,6 +24685,12 @@ func UnmarshalBertyEntityConversationMemberInput(v interface{}) (entity.Conversa
if err != nil {
return it, err
}
+ case "wroteAt":
+ var err error
+ it.WroteAt, err = models.UnmarshalTime(v)
+ if err != nil {
+ return it, err
+ }
case "status":
var err error
@@ -25480,6 +25594,7 @@ type BertyEntityConversation implements Node {
createdAt: GoogleProtobufTimestamp
updatedAt: GoogleProtobufTimestamp
readAt: GoogleProtobufTimestamp
+ wroteAt: GoogleProtobufTimestamp
title: String!
topic: String!
infos: String!
@@ -25492,6 +25607,7 @@ type BertyEntityConversationMember implements Node {
createdAt: GoogleProtobufTimestamp
updatedAt: GoogleProtobufTimestamp
readAt: GoogleProtobufTimestamp
+ wroteAt: GoogleProtobufTimestamp
status: Enum
contact: BertyEntityContact
conversationId: ID!
@@ -25976,27 +26092,29 @@ input BertyEntityContactInput {
overrideDisplayName: String!
overrideDisplayStatus: String!
}
+input BertyEntityConversationMemberInput {
+ id: ID!
+ createdAt: GoogleProtobufTimestampInput
+ updatedAt: GoogleProtobufTimestampInput
+ readAt: GoogleProtobufTimestampInput
+ wroteAt: GoogleProtobufTimestampInput
+ status: Enum
+ contact: BertyEntityContactInput
+ conversationId: ID!
+ contactId: ID!
+}
input BertyEntityConversationInput {
id: ID!
createdAt: GoogleProtobufTimestampInput
updatedAt: GoogleProtobufTimestampInput
readAt: GoogleProtobufTimestampInput
+ wroteAt: GoogleProtobufTimestampInput
title: String!
topic: String!
infos: String!
kind: Enum
members: [BertyEntityConversationMemberInput]
}
-input BertyEntityConversationMemberInput {
- id: ID!
- createdAt: GoogleProtobufTimestampInput
- updatedAt: GoogleProtobufTimestampInput
- readAt: GoogleProtobufTimestampInput
- status: Enum
- contact: BertyEntityContactInput
- conversationId: ID!
- contactId: ID!
-}
input BertyEntityMessageInput {
text: String!
}
@@ -26064,6 +26182,7 @@ type Query {
createdAt: GoogleProtobufTimestampInput
updatedAt: GoogleProtobufTimestampInput
readAt: GoogleProtobufTimestampInput
+ wroteAt: GoogleProtobufTimestampInput
title: String!
topic: String!
infos: String!
@@ -26075,6 +26194,7 @@ type Query {
createdAt: GoogleProtobufTimestampInput
updatedAt: GoogleProtobufTimestampInput
readAt: GoogleProtobufTimestampInput
+ wroteAt: GoogleProtobufTimestampInput
status: Enum
contact: BertyEntityContactInput
conversationId: ID!
@@ -26192,6 +26312,7 @@ type Mutation {
createdAt: GoogleProtobufTimestampInput
updatedAt: GoogleProtobufTimestampInput
readAt: GoogleProtobufTimestampInput
+ wroteAt: GoogleProtobufTimestampInput
title: String!
topic: String!
infos: String!
diff --git a/core/api/node/graphql/resolver.go b/core/api/node/graphql/resolver.go
index b297deb8c9..b23c1e8eb4 100644
--- a/core/api/node/graphql/resolver.go
+++ b/core/api/node/graphql/resolver.go
@@ -756,7 +756,7 @@ func (r *queryResolver) ContactCheckPublicKey(ctx context.Context, contact *enti
})
}
-func (r *mutationResolver) ConversationUpdate(ctx context.Context, id string, createdAt, updatedAt, readAt *time.Time, title, topic string, infos string, kind *int32, members []*entity.ConversationMember) (*entity.Conversation, error) {
+func (r *mutationResolver) ConversationUpdate(ctx context.Context, id string, createdAt, updatedAt, readAt *time.Time, wroteAt *time.Time, title, topic string, infos string, kind *int32, members []*entity.ConversationMember) (*entity.Conversation, error) {
if id == "" {
return nil, errors.New("no id supplied")
}
@@ -798,7 +798,7 @@ func (r *mutationResolver) ConversationRemove(ctx context.Context, id string) (*
})
}
-func (r *queryResolver) Conversation(ctx context.Context, id string, createdAt, updatedAt, readAt *time.Time, title, topic string, infos string, kind *int32, members []*entity.ConversationMember) (*entity.Conversation, error) {
+func (r *queryResolver) Conversation(ctx context.Context, id string, createdAt, updatedAt, readAt *time.Time, wroteAt *time.Time, title, topic string, infos string, kind *int32, members []*entity.ConversationMember) (*entity.Conversation, error) {
if id != "" {
id = strings.SplitN(id, ":", 2)[1]
}
@@ -815,7 +815,7 @@ func (r *queryResolver) Conversation(ctx context.Context, id string, createdAt,
ID: id,
})
}
-func (r *queryResolver) ConversationMember(ctx context.Context, id string, createAt, updatedAt *time.Time, readAt *time.Time, status *int32, contact *entity.Contact, conversationID, contactID string) (*entity.ConversationMember, error) {
+func (r *queryResolver) ConversationMember(ctx context.Context, id string, createAt, updatedAt *time.Time, readAt *time.Time, wroteAt *time.Time, status *int32, contact *entity.Contact, conversationID, contactID string) (*entity.ConversationMember, error) {
if id != "" {
id = strings.SplitN(id, ":", 2)[1]
}
diff --git a/core/api/node/graphql/service.gen.graphql b/core/api/node/graphql/service.gen.graphql
index 69f0eac413..ec0a9a8bc2 100644
--- a/core/api/node/graphql/service.gen.graphql
+++ b/core/api/node/graphql/service.gen.graphql
@@ -298,6 +298,7 @@ type BertyEntityConversation implements Node {
createdAt: GoogleProtobufTimestamp
updatedAt: GoogleProtobufTimestamp
readAt: GoogleProtobufTimestamp
+ wroteAt: GoogleProtobufTimestamp
title: String!
topic: String!
infos: String!
@@ -310,6 +311,7 @@ type BertyEntityConversationMember implements Node {
createdAt: GoogleProtobufTimestamp
updatedAt: GoogleProtobufTimestamp
readAt: GoogleProtobufTimestamp
+ wroteAt: GoogleProtobufTimestamp
status: Enum
contact: BertyEntityContact
conversationId: ID!
@@ -794,27 +796,29 @@ input BertyEntityContactInput {
overrideDisplayName: String!
overrideDisplayStatus: String!
}
+input BertyEntityConversationMemberInput {
+ id: ID!
+ createdAt: GoogleProtobufTimestampInput
+ updatedAt: GoogleProtobufTimestampInput
+ readAt: GoogleProtobufTimestampInput
+ wroteAt: GoogleProtobufTimestampInput
+ status: Enum
+ contact: BertyEntityContactInput
+ conversationId: ID!
+ contactId: ID!
+}
input BertyEntityConversationInput {
id: ID!
createdAt: GoogleProtobufTimestampInput
updatedAt: GoogleProtobufTimestampInput
readAt: GoogleProtobufTimestampInput
+ wroteAt: GoogleProtobufTimestampInput
title: String!
topic: String!
infos: String!
kind: Enum
members: [BertyEntityConversationMemberInput]
}
-input BertyEntityConversationMemberInput {
- id: ID!
- createdAt: GoogleProtobufTimestampInput
- updatedAt: GoogleProtobufTimestampInput
- readAt: GoogleProtobufTimestampInput
- status: Enum
- contact: BertyEntityContactInput
- conversationId: ID!
- contactId: ID!
-}
input BertyEntityMessageInput {
text: String!
}
@@ -882,6 +886,7 @@ type Query {
createdAt: GoogleProtobufTimestampInput
updatedAt: GoogleProtobufTimestampInput
readAt: GoogleProtobufTimestampInput
+ wroteAt: GoogleProtobufTimestampInput
title: String!
topic: String!
infos: String!
@@ -893,6 +898,7 @@ type Query {
createdAt: GoogleProtobufTimestampInput
updatedAt: GoogleProtobufTimestampInput
readAt: GoogleProtobufTimestampInput
+ wroteAt: GoogleProtobufTimestampInput
status: Enum
contact: BertyEntityContactInput
conversationId: ID!
@@ -1010,6 +1016,7 @@ type Mutation {
createdAt: GoogleProtobufTimestampInput
updatedAt: GoogleProtobufTimestampInput
readAt: GoogleProtobufTimestampInput
+ wroteAt: GoogleProtobufTimestampInput
title: String!
topic: String!
infos: String!
diff --git a/core/entity/conversation.go b/core/entity/conversation.go
index 2dc0661751..9bffe39905 100644
--- a/core/entity/conversation.go
+++ b/core/entity/conversation.go
@@ -10,14 +10,7 @@ import (
"github.com/gofrs/uuid"
)
-type ConversationInteractive interface {
- ConversationInformative
-
- // only member should interact on conversation, not conversation itself
- GetInteractiveMember(contactID string) (ConversationMemberInteractive, error)
-}
-
-type ConversationInformative interface {
+type ConversationInteractor interface {
IsOneToOne() bool
IsGroup() bool
@@ -25,15 +18,17 @@ type ConversationInformative interface {
IsMember(contactID string) bool
- GetMember(contactID string) (ConversationMemberInformative, error)
+ GetMember(contactID string) (ConversationMemberInteractor, error)
- GetOwners() []ConversationMemberInformative
+ GetOwners() []ConversationMemberInteractor
GetComputedTitle() string
+
+ Marshal() ([]byte, error)
+ Unmarshal([]byte) error
}
-var _ ConversationInteractive = (*Conversation)(nil)
-var _ ConversationInformative = (*Conversation)(nil)
+var _ ConversationInteractor = (*Conversation)(nil)
func NewOneToOneConversation(a *Contact, b *Contact) (*Conversation, error) {
c := &Conversation{
@@ -43,18 +38,18 @@ func NewOneToOneConversation(a *Contact, b *Contact) (*Conversation, error) {
}
// create the first member
- ma, err := NewConversationMember(a, c)
+ ma, err := newConversationMember(a, c)
if err != nil {
return nil, errorcodes.ErrConversation.Wrap(err)
}
- mb, err := NewConversationMember(b, c)
+ mb, err := newConversationMember(b, c)
if err != nil {
return nil, errorcodes.ErrConversation.Wrap(err)
}
c.Members = append(c.Members, ma, mb)
- im, err := c.GetInteractiveMember(ma.GetContactID())
+ im, err := c.GetMember(ma.GetContactID())
if err != nil {
return nil, errorcodes.ErrConversation.Wrap(err)
}
@@ -92,14 +87,14 @@ func NewGroupConversation(contacts []*Contact) (*Conversation, error) {
}
// add myself as converastion member
- mm, err := NewConversationMember(myself, c)
+ mm, err := newConversationMember(myself, c)
if err != nil {
return nil, errorcodes.ErrConversation.Wrap(err)
}
c.Members = append(c.Members, mm)
// get interactive member
- im, err := c.GetInteractiveMember(myself.ID)
+ im, err := c.GetMember(myself.ID)
if err != nil {
return nil, err
}
@@ -159,26 +154,14 @@ func (c *Conversation) IsGroup() bool {
return true
}
-// GetInteractiveMember returns a member that can interact with conversation
-func (c *Conversation) GetInteractiveMember(contactID string) (ConversationMemberInteractive, error) {
- for _, member := range c.Members {
- if member.ContactID == contactID {
- copy := *member
- copy.Conversation = c
- return ©, nil
- }
- }
- return nil, errorcodes.ErrConversationGetInteractiveMember.Wrap(
- errorcodes.ErrConversationMembers.Wrap(
- errorcodes.ErrConversationMemberContactID.New(),
- ),
- )
-}
-
-func (c *Conversation) GetMember(contactID string) (ConversationMemberInformative, error) {
+// GetMember returns a member that can interact with conversation
+func (c *Conversation) GetMember(contactID string) (ConversationMemberInteractor, error) {
for _, member := range c.Members {
if member.ContactID == contactID {
- return member, nil
+ return &conversationMember{
+ ConversationMember: member,
+ conversation: c,
+ }, nil
}
}
return nil, errorcodes.ErrConversationGetMember.Wrap(
@@ -188,11 +171,14 @@ func (c *Conversation) GetMember(contactID string) (ConversationMemberInformativ
)
}
-func (c *Conversation) GetOwners() []ConversationMemberInformative {
- owners := []ConversationMemberInformative{}
+func (c *Conversation) GetOwners() []ConversationMemberInteractor {
+ owners := []ConversationMemberInteractor{}
for _, member := range c.Members {
if member.Status == ConversationMember_Owner {
- owners = append(owners, member)
+ owners = append(owners, &conversationMember{
+ ConversationMember: member,
+ conversation: c,
+ })
}
}
return owners
@@ -248,14 +234,13 @@ func (c Conversation) Filtered() *Conversation {
Title: c.Title,
Topic: c.Topic,
Kind: c.Kind,
+ ReadAt: c.ReadAt,
Members: filteredMembers,
}
}
// Conversation Member takes actions on conversation
-type ConversationMemberInteractive interface {
- ConversationMemberInformative
-
+type ConversationMemberInteractor interface {
Invite(contact *Contact) error
Leave() error
@@ -268,23 +253,28 @@ type ConversationMemberInteractive interface {
Unblock(contactID string) error
Read(time.Time) error
- Write(*Message) error
-}
+ Write(time.Time, *Message) error
-type ConversationMemberInformative interface {
IsOwner() bool
IsActive() bool
IsBlocked() bool
+ Marshal() ([]byte, error)
+ Unmarshal([]byte) error
+
GetContactID() string
GetContact() *Contact
GetConversationID() string
}
-var _ ConversationMemberInformative = (*ConversationMember)(nil)
-var _ ConversationMemberInteractive = (*ConversationMember)(nil)
+type conversationMember struct {
+ *ConversationMember
+ conversation *Conversation
+}
+
+var _ ConversationMemberInteractor = (*conversationMember)(nil)
-func NewConversationMember(contact *Contact, conversation *Conversation) (*ConversationMember, error) {
+func newConversationMember(contact *Contact, conversation *Conversation) (*ConversationMember, error) {
m := &ConversationMember{
ID: conversation.ID + ":" + contact.ID,
Status: ConversationMember_Active,
@@ -295,47 +285,44 @@ func NewConversationMember(contact *Contact, conversation *Conversation) (*Conve
return m, nil
}
-func (m *ConversationMember) IsOwner() bool {
+func (m *conversationMember) IsOwner() bool {
if m.Status == ConversationMember_Owner {
return true
}
- // only for interactive member
- if m.Conversation != nil {
- // if conversation is 1 to 1, member is automatically owner
- if m.Conversation.Kind == Conversation_OneToOne {
- return true
- }
+ // if conversation is 1 to 1, member is automatically owner
+ if m.conversation.Kind == Conversation_OneToOne {
+ return true
+ }
- // if there is no member in conversation, member is automatically owner
- if len(m.Conversation.Members) == 0 {
- return true
- }
+ // if there is no member in conversation, member is automatically owner
+ if len(m.conversation.Members) == 0 {
+ return true
+ }
- // if there is no owner, member is automatically owner
- if len(m.Conversation.GetOwners()) == 0 {
- return true
- }
+ // if there is no owner, member is automatically owner
+ if len(m.conversation.GetOwners()) == 0 {
+ return true
}
return false
}
-func (m *ConversationMember) IsActive() bool {
+func (m *conversationMember) IsActive() bool {
if m.Status == ConversationMember_Active || m.IsOwner() {
return true
}
return false
}
-func (m *ConversationMember) IsBlocked() bool {
+func (m *conversationMember) IsBlocked() bool {
if m.Status == ConversationMember_Blocked {
return true
}
return false
}
-func (m *ConversationMember) Invite(contact *Contact) error {
+func (m *conversationMember) Invite(contact *Contact) error {
// check if member have the right to invite
if !m.IsActive() {
return errorcodes.ErrConversationMemberInvite.Wrap(
@@ -344,40 +331,31 @@ func (m *ConversationMember) Invite(contact *Contact) error {
}
// check if contact is already a member
- if m.Conversation.IsMember(contact.ID) {
+ if m.conversation.IsMember(contact.ID) {
return nil
}
// check if we can add the member
- if m.Conversation.IsFull() {
+ if m.conversation.IsFull() {
return errorcodes.ErrConversationMemberInvite.Wrap(
errorcodes.ErrConversationIsFull.New(),
)
}
// then add the member
- cm, err := NewConversationMember(contact, m.Conversation)
+ cm, err := newConversationMember(contact, m.conversation)
if err != nil {
return errorcodes.ErrConversationMemberInvite.Wrap(err)
}
- m.Conversation.Members = append(m.Conversation.Members, cm)
+ m.conversation.Members = append(m.conversation.Members, cm)
return nil
}
-func (m *ConversationMember) Leave() error {
- // check if the member is the only owner
- if m.IsOwner() && len(m.Conversation.GetOwners()) == 1 {
- return errorcodes.ErrConversationMemberLeave.Wrap(
- errorcodes.ErrConversationMemberStatus.Wrap(
- errorcodes.ErrConversationGetOwners.New(),
- ),
- )
- }
-
+func (m *conversationMember) Leave() error {
// retrieve member in list and remove it
- for i, member := range m.Conversation.Members {
+ for i, member := range m.conversation.Members {
if m.ID == member.ID {
- m.Conversation.Members = append(m.Conversation.Members[:i], m.Conversation.Members[i+1:]...)
+ m.conversation.Members = append(m.conversation.Members[:i], m.conversation.Members[i+1:]...)
return nil
}
}
@@ -387,7 +365,7 @@ func (m *ConversationMember) Leave() error {
)
}
-func (m *ConversationMember) SetTitle(title string) error {
+func (m *conversationMember) SetTitle(title string) error {
// check if member have the right to set the title
if !m.IsOwner() {
return errorcodes.ErrConversationMemberSetTitle.Wrap(
@@ -403,11 +381,11 @@ func (m *ConversationMember) SetTitle(title string) error {
}
// then set the title
- m.Conversation.Title = title
+ m.conversation.Title = title
return nil
}
-func (m *ConversationMember) SetTopic(topic string) error {
+func (m *conversationMember) SetTopic(topic string) error {
// check if member have the right to set the topic
if !m.IsOwner() {
return errorcodes.ErrConversationMemberSetTopic.Wrap(
@@ -416,11 +394,11 @@ func (m *ConversationMember) SetTopic(topic string) error {
}
// then set the topic
- m.Conversation.Topic = topic
+ m.conversation.Topic = topic
return nil
}
-func (m *ConversationMember) SetOwner(contactID string) error {
+func (m *conversationMember) SetOwner(contactID string) error {
// check if member have the right to set new owner
if !m.IsOwner() {
return errorcodes.ErrConversationMemberSetOwner.Wrap(
@@ -428,7 +406,7 @@ func (m *ConversationMember) SetOwner(contactID string) error {
)
}
- for _, member := range m.Conversation.Members {
+ for _, member := range m.conversation.Members {
if member.Contact.ID == contactID {
member.Status = ConversationMember_Owner
return nil
@@ -442,7 +420,7 @@ func (m *ConversationMember) SetOwner(contactID string) error {
)
}
-func (m *ConversationMember) Block(contactID string) error {
+func (m *conversationMember) Block(contactID string) error {
// check if member have the right to block
if !m.IsOwner() {
return errorcodes.ErrConversationMemberBlock.Wrap(
@@ -451,7 +429,7 @@ func (m *ConversationMember) Block(contactID string) error {
}
// check if contact is an owner
- cm, err := m.Conversation.GetInteractiveMember(contactID)
+ cm, err := m.conversation.GetMember(contactID)
if err != nil {
return errorcodes.ErrConversationMemberBlock.Wrap(err)
}
@@ -464,7 +442,7 @@ func (m *ConversationMember) Block(contactID string) error {
}
// then block the contact
- for _, member := range m.Conversation.Members {
+ for _, member := range m.conversation.Members {
if member.Contact.ID == contactID {
member.Status = ConversationMember_Blocked
return nil
@@ -478,7 +456,7 @@ func (m *ConversationMember) Block(contactID string) error {
)
}
-func (m *ConversationMember) Unblock(contactID string) error {
+func (m *conversationMember) Unblock(contactID string) error {
// check if member have the right to unblock
if !m.IsOwner() {
return errorcodes.ErrConversationMemberUnblock.Wrap(
@@ -486,7 +464,7 @@ func (m *ConversationMember) Unblock(contactID string) error {
)
}
- for _, member := range m.Conversation.Members {
+ for _, member := range m.conversation.Members {
if member.Contact.ID == contactID {
member.Status = ConversationMember_Active
return nil
@@ -500,7 +478,7 @@ func (m *ConversationMember) Unblock(contactID string) error {
)
}
-func (m *ConversationMember) Read(at time.Time) error {
+func (m *conversationMember) Read(at time.Time) error {
// check if member have the right to read
if !m.IsActive() {
return errorcodes.ErrConversationMemberRead.Wrap(
@@ -508,25 +486,15 @@ func (m *ConversationMember) Read(at time.Time) error {
)
}
- m.ReadAt = at
- for _, member := range m.Conversation.Members {
- if member.Contact.ID == m.Contact.ID {
- member.ReadAt = at
-
- // say that conversation has been read by at least one user
- m.Conversation.ReadAt = at
- return nil
- }
- }
+ at = at.UTC()
- return errorcodes.ErrConversationMemberRead.Wrap(
- errorcodes.ErrConversationMembers.Wrap(
- errorcodes.ErrConversationMemberContactID.New(),
- ),
- )
+ m.ReadAt = at
+ // say that conversation has been read by at least one user
+ m.conversation.ReadAt = at
+ return nil
}
-func (m *ConversationMember) Write(message *Message) error {
+func (m *conversationMember) Write(at time.Time, message *Message) error {
// check if member have the right to write
if !m.IsActive() {
return errorcodes.ErrConversationMemberWrite.Wrap(
@@ -534,30 +502,30 @@ func (m *ConversationMember) Write(message *Message) error {
)
}
- now := time.Now()
- m.ReadAt = now
- for _, member := range m.Conversation.Members {
- if member.Contact.ID == m.Contact.ID {
- member.ReadAt = now
-
- // say that conversation has not been read by others members
- m.Conversation.ReadAt = time.Time{}
+ at = at.UTC()
- if m.Conversation.IsOneToOne() {
- m.Conversation.Infos = message.Text
- } else {
- m.Conversation.Infos = m.Contact.DisplayName + ": " + message.Text
- }
+ m.ReadAt = at
+ m.WroteAt = at
+ m.conversation.WroteAt = at
- return nil
- }
+ if m.conversation.IsOneToOne() {
+ m.conversation.Infos = message.Text
+ } else {
+ m.conversation.Infos = m.Contact.DisplayName + ": " + message.Text
}
- return errorcodes.ErrConversationMemberWrite.Wrap(
- errorcodes.ErrConversationMembers.Wrap(
- errorcodes.ErrConversationMemberContactID.New(),
- ),
- )
+ return nil
+}
+
+func (m conversationMember) Filtered() *ConversationMember {
+ member := ConversationMember{
+ ID: m.ID,
+ Status: m.Status,
+ }
+ if m.Contact != nil {
+ member.Contact = m.Contact.Filtered()
+ }
+ return &member
}
func (m ConversationMember) Filtered() *ConversationMember {
diff --git a/core/entity/conversation.pb.go b/core/entity/conversation.pb.go
index 8a24341e07..2c24261ac6 100644
--- a/core/entity/conversation.pb.go
+++ b/core/entity/conversation.pb.go
@@ -93,11 +93,12 @@ type Conversation struct {
CreatedAt time.Time `protobuf:"bytes,2,opt,name=created_at,json=createdAt,proto3,stdtime" json:"created_at"`
UpdatedAt time.Time `protobuf:"bytes,3,opt,name=updated_at,json=updatedAt,proto3,stdtime" json:"updated_at"`
ReadAt time.Time `protobuf:"bytes,4,opt,name=read_at,json=readAt,proto3,stdtime" json:"read_at"`
+ WroteAt time.Time `protobuf:"bytes,5,opt,name=wrote_at,json=wroteAt,proto3,stdtime" json:"wrote_at"`
Title string `protobuf:"bytes,20,opt,name=title,proto3" json:"title,omitempty"`
Topic string `protobuf:"bytes,21,opt,name=topic,proto3" json:"topic,omitempty"`
Infos string `protobuf:"bytes,22,opt,name=infos,proto3" json:"infos,omitempty"`
Kind Conversation_Kind `protobuf:"varint,23,opt,name=kind,proto3,enum=berty.entity.Conversation_Kind" json:"kind,omitempty"`
- Members []*ConversationMember `protobuf:"bytes,100,rep,name=members,proto3" json:"members,omitempty" gorm:"foreignkey:ConversationID;association_foreignkey:ID"`
+ Members []*ConversationMember `protobuf:"bytes,100,rep,name=members,proto3" json:"members,omitempty" gorm:"foreignkey:ConversationID;association_foreignkey:ID;save_associations:true"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@@ -164,6 +165,13 @@ func (m *Conversation) GetReadAt() time.Time {
return time.Time{}
}
+func (m *Conversation) GetWroteAt() time.Time {
+ if m != nil {
+ return m.WroteAt
+ }
+ return time.Time{}
+}
+
func (m *Conversation) GetTitle() string {
if m != nil {
return m.Title
@@ -204,11 +212,11 @@ type ConversationMember struct {
CreatedAt time.Time `protobuf:"bytes,2,opt,name=created_at,json=createdAt,proto3,stdtime" json:"created_at"`
UpdatedAt time.Time `protobuf:"bytes,3,opt,name=updated_at,json=updatedAt,proto3,stdtime" json:"updated_at"`
ReadAt time.Time `protobuf:"bytes,4,opt,name=read_at,json=readAt,proto3,stdtime" json:"read_at"`
+ WroteAt time.Time `protobuf:"bytes,5,opt,name=wrote_at,json=wroteAt,proto3,stdtime" json:"wrote_at"`
Status ConversationMember_Status `protobuf:"varint,10,opt,name=status,proto3,enum=berty.entity.ConversationMember_Status" json:"status,omitempty"`
- Contact *Contact `protobuf:"bytes,100,opt,name=contact,proto3" json:"contact,omitempty"`
+ Contact *Contact `protobuf:"bytes,100,opt,name=contact,proto3" json:"contact,omitempty" gorm:"association_autoupdate:false;association_create:true"`
ConversationID string `protobuf:"bytes,101,opt,name=conversation_id,json=conversationId,proto3" json:"conversation_id,omitempty"`
ContactID string `protobuf:"bytes,102,opt,name=contact_id,json=contactId,proto3" json:"contact_id,omitempty"`
- Conversation *Conversation `protobuf:"bytes,103,opt,name=conversation,proto3" json:"conversation,omitempty" gorm:"PRELOAD:false;foreignkey:ID;association_foreignkey:ConversationID"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@@ -275,6 +283,13 @@ func (m *ConversationMember) GetReadAt() time.Time {
return time.Time{}
}
+func (m *ConversationMember) GetWroteAt() time.Time {
+ if m != nil {
+ return m.WroteAt
+ }
+ return time.Time{}
+}
+
func (m *ConversationMember) GetStatus() ConversationMember_Status {
if m != nil {
return m.Status
@@ -303,13 +318,6 @@ func (m *ConversationMember) GetContactID() string {
return ""
}
-func (m *ConversationMember) GetConversation() *Conversation {
- if m != nil {
- return m.Conversation
- }
- return nil
-}
-
func init() {
proto.RegisterEnum("berty.entity.Conversation_Kind", Conversation_Kind_name, Conversation_Kind_value)
proto.RegisterEnum("berty.entity.ConversationMember_Status", ConversationMember_Status_name, ConversationMember_Status_value)
@@ -320,51 +328,51 @@ func init() {
func init() { proto.RegisterFile("entity/conversation.proto", fileDescriptor_6f1357e67b20af82) }
var fileDescriptor_6f1357e67b20af82 = []byte{
- // 693 bytes of a gzipped FileDescriptorProto
- 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe4, 0x54, 0xcd, 0x6e, 0xd3, 0x4a,
- 0x18, 0xcd, 0xa4, 0xf9, 0x69, 0xa6, 0x51, 0x6f, 0x34, 0x4a, 0x7b, 0xdd, 0x5c, 0x29, 0x8e, 0xac,
- 0x2b, 0xdd, 0x2c, 0xae, 0x1c, 0xa9, 0xed, 0xa6, 0xa9, 0x00, 0xc5, 0x0d, 0x82, 0x08, 0x50, 0x2a,
- 0x53, 0x36, 0x6c, 0xa2, 0x89, 0x3d, 0x71, 0x47, 0x89, 0x3d, 0x66, 0x3c, 0x69, 0x15, 0xb6, 0x7d,
- 0x81, 0x2e, 0xfb, 0x08, 0xac, 0x10, 0x4b, 0x1e, 0xa1, 0x4b, 0x96, 0xac, 0x42, 0x15, 0x5e, 0x00,
- 0xfa, 0x04, 0xc8, 0x63, 0x9b, 0x3a, 0x54, 0x15, 0xea, 0x9a, 0x55, 0xfc, 0x7d, 0x73, 0xce, 0xf1,
- 0x77, 0xe6, 0x3b, 0x31, 0xdc, 0x22, 0x9e, 0xa0, 0x62, 0xd6, 0xb2, 0x98, 0x77, 0x42, 0x78, 0x80,
- 0x05, 0x65, 0x9e, 0xee, 0x73, 0x26, 0x18, 0x2a, 0x0f, 0x09, 0x17, 0x33, 0x3d, 0x02, 0xd4, 0xaa,
- 0x0e, 0x73, 0x98, 0x3c, 0x68, 0x85, 0x4f, 0x11, 0xa6, 0xa6, 0x3a, 0x8c, 0x39, 0x13, 0xd2, 0x92,
- 0xd5, 0x70, 0x3a, 0x6a, 0x09, 0xea, 0x92, 0x40, 0x60, 0xd7, 0x8f, 0x01, 0xff, 0xf8, 0x63, 0xa7,
- 0x75, 0x82, 0x27, 0xd4, 0xc6, 0x82, 0xfc, 0x7c, 0x88, 0x0f, 0x35, 0xec, 0xd3, 0x1b, 0xaa, 0xc3,
- 0xb1, 0x7f, 0xfc, 0x66, 0x92, 0xfc, 0xc6, 0x98, 0xea, 0xcd, 0x80, 0x02, 0x5b, 0xe2, 0x97, 0xae,
- 0x4b, 0x82, 0x00, 0x3b, 0x89, 0x5e, 0x25, 0xee, 0x12, 0xce, 0xa3, 0x8e, 0xf6, 0x3e, 0x07, 0xcb,
- 0x07, 0x29, 0x6b, 0x68, 0x17, 0x66, 0xa9, 0xad, 0x80, 0x06, 0x68, 0x96, 0x8c, 0x7f, 0xaf, 0xbe,
- 0x6d, 0x81, 0x8f, 0x67, 0x35, 0xb0, 0x98, 0xab, 0xd9, 0x5e, 0xf7, 0x7a, 0xae, 0x22, 0x87, 0x71,
- 0xb7, 0xad, 0xf9, 0x9c, 0xba, 0x98, 0xcf, 0x06, 0x63, 0x32, 0xd3, 0xcc, 0x2c, 0xb5, 0xd1, 0x01,
- 0x84, 0x16, 0x27, 0x58, 0x10, 0x7b, 0x80, 0x85, 0x92, 0x6d, 0x80, 0xe6, 0xda, 0x76, 0x4d, 0x8f,
- 0xbc, 0xeb, 0x89, 0x01, 0xfd, 0x28, 0xf1, 0x6e, 0xac, 0x5e, 0xce, 0xd5, 0xcc, 0xf9, 0x17, 0x15,
- 0x98, 0xa5, 0x98, 0xd7, 0x11, 0xa1, 0xc8, 0xd4, 0xb7, 0x13, 0x91, 0x95, 0xfb, 0x88, 0xc4, 0xbc,
- 0x8e, 0x40, 0x0f, 0x60, 0x91, 0x13, 0x2c, 0x15, 0x72, 0xf7, 0x50, 0x28, 0x84, 0xa4, 0x8e, 0x40,
- 0x55, 0x98, 0x17, 0x54, 0x4c, 0x88, 0x52, 0x0d, 0x6f, 0xc0, 0x8c, 0x0a, 0xd9, 0x65, 0x3e, 0xb5,
- 0x94, 0x8d, 0xb8, 0x1b, 0x16, 0x61, 0x97, 0x7a, 0x23, 0x16, 0x28, 0x9b, 0x51, 0x57, 0x16, 0x68,
- 0x07, 0xe6, 0xc6, 0xd4, 0xb3, 0x95, 0xbf, 0x1b, 0xa0, 0xb9, 0xbe, 0xad, 0xea, 0xe9, 0x90, 0xe8,
- 0xe9, 0xab, 0xd6, 0x9f, 0x51, 0xcf, 0x36, 0x25, 0x18, 0xbd, 0x85, 0x45, 0x97, 0xb8, 0x43, 0xc2,
- 0x03, 0xc5, 0x6e, 0xac, 0x34, 0xd7, 0xb6, 0x1b, 0x77, 0xf3, 0x5e, 0x48, 0xa0, 0xf1, 0xf0, 0x7a,
- 0xae, 0xb6, 0xa3, 0x75, 0x8c, 0x18, 0x27, 0xd4, 0xf1, 0xc6, 0x64, 0xd6, 0x4e, 0x03, 0x7b, 0xdd,
- 0x7d, 0x1c, 0x04, 0xcc, 0xa2, 0xb2, 0x1a, 0xa4, 0x50, 0xbd, 0xae, 0x66, 0x26, 0x2f, 0xd4, 0xfe,
- 0x87, 0xb9, 0x70, 0x12, 0xb4, 0x06, 0x8b, 0xaf, 0xbc, 0xb1, 0xc7, 0x4e, 0xbd, 0x4a, 0x06, 0x95,
- 0xe1, 0x6a, 0xdf, 0x23, 0x47, 0xac, 0xef, 0x91, 0x0a, 0x40, 0x25, 0x98, 0x7f, 0xc2, 0xd9, 0xd4,
- 0xaf, 0x64, 0xb5, 0xcf, 0x79, 0x88, 0x6e, 0x4f, 0xf3, 0xa7, 0xc7, 0xe6, 0x11, 0x2c, 0x04, 0x02,
- 0x8b, 0x69, 0xa0, 0x40, 0xb9, 0xf6, 0xff, 0x7e, 0xb7, 0x3e, 0xfd, 0xa5, 0x84, 0x9b, 0x31, 0x0d,
- 0xed, 0xc1, 0x62, 0xfc, 0x07, 0x56, 0x6c, 0xf9, 0xfe, 0x8d, 0x5b, 0x0a, 0xe1, 0xa1, 0xb1, 0xfa,
- 0xee, 0xac, 0x06, 0x3e, 0x9c, 0xd5, 0x32, 0x66, 0x82, 0x47, 0x07, 0xf0, 0xaf, 0xf4, 0xc7, 0x69,
- 0x40, 0x6d, 0x85, 0xc8, 0x3d, 0xd4, 0x52, 0x7b, 0x58, 0x5f, 0x0e, 0x86, 0xb9, 0x9e, 0xa6, 0xf4,
- 0x6c, 0xb4, 0x0b, 0x61, 0xac, 0x17, 0xf2, 0x47, 0x92, 0xbf, 0x91, 0xe2, 0x97, 0xe2, 0x01, 0x7a,
- 0x5d, 0xb3, 0x14, 0x03, 0x7b, 0x36, 0x3a, 0x07, 0xb0, 0x9c, 0x16, 0x52, 0x9c, 0xf8, 0xee, 0xee,
- 0x74, 0x6f, 0x1c, 0x5e, 0x7c, 0xdf, 0x02, 0xd7, 0x73, 0xf5, 0x69, 0x14, 0x89, 0x43, 0xf3, 0xf1,
- 0xf3, 0x7e, 0xa7, 0xdb, 0x1e, 0xe1, 0x49, 0x40, 0xf6, 0x97, 0x22, 0x7a, 0x57, 0x78, 0x97, 0x9d,
- 0x68, 0xe6, 0xd2, 0x04, 0xda, 0x1e, 0x2c, 0x44, 0x57, 0xbb, 0x9c, 0xe7, 0x12, 0xcc, 0xf7, 0x4f,
- 0x3d, 0xc2, 0x2b, 0x00, 0x41, 0x58, 0xe8, 0x58, 0x82, 0x9e, 0x90, 0x4a, 0x36, 0xc4, 0x18, 0x13,
- 0x66, 0x8d, 0x89, 0x5d, 0x59, 0x31, 0x9a, 0x97, 0x8b, 0x3a, 0xf8, 0xb4, 0xa8, 0x83, 0xab, 0x45,
- 0x1d, 0x5c, 0x7c, 0xad, 0x67, 0x5e, 0x6f, 0x46, 0x3e, 0x04, 0xb1, 0x8e, 0x5b, 0x16, 0xe3, 0xa4,
- 0x15, 0x39, 0x1a, 0x16, 0x64, 0x28, 0x76, 0x7e, 0x04, 0x00, 0x00, 0xff, 0xff, 0x06, 0x17, 0x0a,
- 0x8e, 0x1d, 0x06, 0x00, 0x00,
+ // 696 bytes of a gzipped FileDescriptorProto
+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x54, 0xcf, 0x6a, 0x13, 0x41,
+ 0x18, 0xcf, 0xa4, 0x4d, 0xd2, 0x4c, 0x4b, 0x0d, 0x43, 0x5a, 0xb7, 0x11, 0xb2, 0x61, 0x11, 0xcc,
+ 0x41, 0x36, 0xd0, 0xf6, 0x62, 0x8a, 0x94, 0xa4, 0x81, 0x12, 0x44, 0x8a, 0x6b, 0x7b, 0xf1, 0x12,
+ 0x26, 0xbb, 0x5f, 0xb6, 0x43, 0x92, 0x9d, 0x75, 0x76, 0x92, 0x9a, 0x73, 0x0f, 0x5e, 0xf5, 0xe6,
+ 0x23, 0x78, 0xf4, 0xe8, 0x0b, 0x08, 0x3d, 0xfa, 0x04, 0xb1, 0xc4, 0x17, 0x90, 0x3e, 0x81, 0xec,
+ 0xec, 0xae, 0xdd, 0x5a, 0x44, 0x8a, 0x57, 0x4f, 0xd9, 0xef, 0xfb, 0x7e, 0xbf, 0x5f, 0xbe, 0x3f,
+ 0x3f, 0x06, 0x6f, 0x81, 0x27, 0x99, 0x9c, 0x35, 0x6c, 0xee, 0x4d, 0x41, 0x04, 0x54, 0x32, 0xee,
+ 0x99, 0xbe, 0xe0, 0x92, 0x93, 0xb5, 0x3e, 0x08, 0x39, 0x33, 0x23, 0x40, 0xa5, 0xec, 0x72, 0x97,
+ 0xab, 0x42, 0x23, 0xfc, 0x8a, 0x30, 0x15, 0xdd, 0xe5, 0xdc, 0x1d, 0x41, 0x43, 0x45, 0xfd, 0xc9,
+ 0xa0, 0x21, 0xd9, 0x18, 0x02, 0x49, 0xc7, 0x7e, 0x0c, 0x78, 0xe0, 0x0f, 0xdd, 0xc6, 0x94, 0x8e,
+ 0x98, 0x43, 0x25, 0xfc, 0xfa, 0x88, 0x8b, 0x06, 0xf5, 0xd9, 0x35, 0xd5, 0x15, 0xd4, 0x3f, 0x7d,
+ 0x3d, 0x4a, 0x7e, 0x63, 0x4c, 0xf9, 0xba, 0x41, 0x49, 0x6d, 0xf9, 0x5b, 0x76, 0x0c, 0x41, 0x40,
+ 0xdd, 0x44, 0xaf, 0x14, 0x67, 0x41, 0x88, 0x28, 0x63, 0xbc, 0xcd, 0xe1, 0xb5, 0x83, 0xd4, 0x68,
+ 0x64, 0x17, 0x67, 0x99, 0xa3, 0xa1, 0x1a, 0xaa, 0x17, 0xdb, 0x0f, 0x2f, 0x7f, 0x6c, 0xa1, 0xcf,
+ 0xe7, 0x15, 0xb4, 0x98, 0xeb, 0xd9, 0x6e, 0xe7, 0x6a, 0xae, 0x13, 0x97, 0x8b, 0x71, 0xd3, 0xf0,
+ 0x05, 0x1b, 0x53, 0x31, 0xeb, 0x0d, 0x61, 0x66, 0x58, 0x59, 0xe6, 0x90, 0x03, 0x8c, 0x6d, 0x01,
+ 0x54, 0x82, 0xd3, 0xa3, 0x52, 0xcb, 0xd6, 0x50, 0x7d, 0x75, 0xbb, 0x62, 0x46, 0xb3, 0x9b, 0xc9,
+ 0x00, 0xe6, 0x71, 0x32, 0x7b, 0x7b, 0xe5, 0x62, 0xae, 0x67, 0xde, 0x7d, 0xd3, 0x91, 0x55, 0x8c,
+ 0x79, 0x2d, 0x19, 0x8a, 0x4c, 0x7c, 0x27, 0x11, 0x59, 0xba, 0x8b, 0x48, 0xcc, 0x6b, 0x49, 0xf2,
+ 0x14, 0x17, 0x04, 0x50, 0xa5, 0xb0, 0x7c, 0x07, 0x85, 0x7c, 0x48, 0x6a, 0x49, 0xb2, 0x8f, 0x57,
+ 0xce, 0x04, 0x97, 0x10, 0xf2, 0x73, 0x77, 0xe0, 0x17, 0x14, 0xab, 0x25, 0x49, 0x19, 0xe7, 0x24,
+ 0x93, 0x23, 0xd0, 0xca, 0xe1, 0x0a, 0xad, 0x28, 0x50, 0x59, 0xee, 0x33, 0x5b, 0xdb, 0x88, 0xb3,
+ 0x61, 0x10, 0x66, 0x99, 0x37, 0xe0, 0x81, 0xb6, 0x19, 0x65, 0x55, 0x40, 0x76, 0xf0, 0xf2, 0x90,
+ 0x79, 0x8e, 0x76, 0xbf, 0x86, 0xea, 0xeb, 0xdb, 0xba, 0x99, 0x76, 0x99, 0x99, 0xbe, 0x95, 0xf9,
+ 0x8c, 0x79, 0x8e, 0xa5, 0xc0, 0xe4, 0x3d, 0xc2, 0x85, 0x31, 0x8c, 0xfb, 0x20, 0x02, 0xcd, 0xa9,
+ 0x2d, 0xd5, 0x57, 0xb7, 0x6b, 0x7f, 0x26, 0x3e, 0x57, 0xc0, 0xf6, 0xc9, 0xd5, 0x5c, 0x7f, 0x11,
+ 0x1d, 0x74, 0xc0, 0x05, 0x30, 0xd7, 0x1b, 0xc2, 0xac, 0x99, 0x06, 0x76, 0x3b, 0x7b, 0x34, 0x08,
+ 0xb8, 0xcd, 0x54, 0xd4, 0x4b, 0xa1, 0xba, 0x9d, 0xbd, 0x80, 0x4e, 0xa1, 0x97, 0x2a, 0x07, 0x4d,
+ 0x29, 0x26, 0x60, 0x58, 0x49, 0x1f, 0xc6, 0x63, 0xbc, 0x1c, 0x76, 0x48, 0x56, 0x71, 0xe1, 0xc4,
+ 0x1b, 0x7a, 0xfc, 0xcc, 0x2b, 0x65, 0xc8, 0x1a, 0x5e, 0x39, 0xf2, 0xe0, 0x98, 0x1f, 0x79, 0x50,
+ 0x42, 0xa4, 0x88, 0x73, 0x87, 0x82, 0x4f, 0xfc, 0x52, 0xd6, 0xf8, 0x92, 0xc3, 0xe4, 0x76, 0x93,
+ 0xff, 0xfd, 0xf8, 0x8f, 0x7e, 0xdc, 0xc7, 0xf9, 0x40, 0x52, 0x39, 0x09, 0x34, 0xac, 0xfc, 0xf4,
+ 0xe8, 0x6f, 0xb6, 0x30, 0x5f, 0x2a, 0xb8, 0x15, 0xd3, 0xc8, 0x1b, 0x5c, 0x88, 0x9f, 0x16, 0xcd,
+ 0x51, 0x0d, 0x6c, 0xdc, 0x52, 0x08, 0x8b, 0xed, 0xc3, 0x8f, 0xe7, 0x15, 0xf4, 0xe9, 0xbc, 0x92,
+ 0xb9, 0x9a, 0xeb, 0x7b, 0xd1, 0x59, 0xd2, 0xde, 0xa1, 0x13, 0xc9, 0xa3, 0xad, 0x34, 0x07, 0x74,
+ 0x14, 0xc0, 0x0d, 0x63, 0x45, 0x3b, 0x4f, 0xfc, 0x13, 0xff, 0x1d, 0x39, 0xc0, 0xf7, 0xd2, 0xaf,
+ 0x6e, 0x8f, 0x39, 0x1a, 0x28, 0x1f, 0x54, 0x52, 0x3e, 0x58, 0xbf, 0xe9, 0x57, 0x6b, 0x3d, 0x4d,
+ 0xe9, 0x3a, 0x64, 0x17, 0xe3, 0x58, 0x2f, 0xe4, 0x0f, 0x14, 0x7f, 0x23, 0xc5, 0x2f, 0xc6, 0xfd,
+ 0x77, 0x3b, 0x56, 0x31, 0x06, 0x76, 0x1d, 0xe3, 0x09, 0xce, 0x47, 0x6b, 0xb8, 0x69, 0xde, 0x22,
+ 0xce, 0x1d, 0x9d, 0x79, 0x20, 0x4a, 0x88, 0x60, 0x9c, 0x6f, 0xd9, 0x92, 0x4d, 0xa1, 0x94, 0x0d,
+ 0x31, 0xed, 0x11, 0xb7, 0x87, 0xe0, 0x94, 0x96, 0xda, 0xf5, 0x8b, 0x45, 0x15, 0x7d, 0x5d, 0x54,
+ 0xd1, 0xe5, 0xa2, 0x8a, 0x3e, 0x7c, 0xaf, 0x66, 0x5e, 0x6d, 0x46, 0xfb, 0x92, 0x60, 0x9f, 0x36,
+ 0x6c, 0x2e, 0xa0, 0x11, 0x6d, 0xae, 0x9f, 0x57, 0x17, 0xdc, 0xf9, 0x19, 0x00, 0x00, 0xff, 0xff,
+ 0x0d, 0x6b, 0x49, 0xa4, 0x63, 0x06, 0x00, 0x00,
}
func (m *Conversation) Marshal() (dAtA []byte, err error) {
@@ -412,6 +420,14 @@ func (m *Conversation) MarshalTo(dAtA []byte) (int, error) {
return 0, err
}
i += n3
+ dAtA[i] = 0x2a
+ i++
+ i = encodeVarintConversation(dAtA, i, uint64(github_com_gogo_protobuf_types.SizeOfStdTime(m.WroteAt)))
+ n4, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.WroteAt, dAtA[i:])
+ if err != nil {
+ return 0, err
+ }
+ i += n4
if len(m.Title) > 0 {
dAtA[i] = 0xa2
i++
@@ -487,27 +503,35 @@ func (m *ConversationMember) MarshalTo(dAtA []byte) (int, error) {
dAtA[i] = 0x12
i++
i = encodeVarintConversation(dAtA, i, uint64(github_com_gogo_protobuf_types.SizeOfStdTime(m.CreatedAt)))
- n4, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.CreatedAt, dAtA[i:])
+ n5, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.CreatedAt, dAtA[i:])
if err != nil {
return 0, err
}
- i += n4
+ i += n5
dAtA[i] = 0x1a
i++
i = encodeVarintConversation(dAtA, i, uint64(github_com_gogo_protobuf_types.SizeOfStdTime(m.UpdatedAt)))
- n5, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.UpdatedAt, dAtA[i:])
+ n6, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.UpdatedAt, dAtA[i:])
if err != nil {
return 0, err
}
- i += n5
+ i += n6
dAtA[i] = 0x22
i++
i = encodeVarintConversation(dAtA, i, uint64(github_com_gogo_protobuf_types.SizeOfStdTime(m.ReadAt)))
- n6, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.ReadAt, dAtA[i:])
+ n7, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.ReadAt, dAtA[i:])
if err != nil {
return 0, err
}
- i += n6
+ i += n7
+ dAtA[i] = 0x2a
+ i++
+ i = encodeVarintConversation(dAtA, i, uint64(github_com_gogo_protobuf_types.SizeOfStdTime(m.WroteAt)))
+ n8, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.WroteAt, dAtA[i:])
+ if err != nil {
+ return 0, err
+ }
+ i += n8
if m.Status != 0 {
dAtA[i] = 0x50
i++
@@ -519,11 +543,11 @@ func (m *ConversationMember) MarshalTo(dAtA []byte) (int, error) {
dAtA[i] = 0x6
i++
i = encodeVarintConversation(dAtA, i, uint64(m.Contact.Size()))
- n7, err := m.Contact.MarshalTo(dAtA[i:])
+ n9, err := m.Contact.MarshalTo(dAtA[i:])
if err != nil {
return 0, err
}
- i += n7
+ i += n9
}
if len(m.ConversationID) > 0 {
dAtA[i] = 0xaa
@@ -541,18 +565,6 @@ func (m *ConversationMember) MarshalTo(dAtA []byte) (int, error) {
i = encodeVarintConversation(dAtA, i, uint64(len(m.ContactID)))
i += copy(dAtA[i:], m.ContactID)
}
- if m.Conversation != nil {
- dAtA[i] = 0xba
- i++
- dAtA[i] = 0x6
- i++
- i = encodeVarintConversation(dAtA, i, uint64(m.Conversation.Size()))
- n8, err := m.Conversation.MarshalTo(dAtA[i:])
- if err != nil {
- return 0, err
- }
- i += n8
- }
if m.XXX_unrecognized != nil {
i += copy(dAtA[i:], m.XXX_unrecognized)
}
@@ -584,6 +596,8 @@ func (m *Conversation) Size() (n int) {
n += 1 + l + sovConversation(uint64(l))
l = github_com_gogo_protobuf_types.SizeOfStdTime(m.ReadAt)
n += 1 + l + sovConversation(uint64(l))
+ l = github_com_gogo_protobuf_types.SizeOfStdTime(m.WroteAt)
+ n += 1 + l + sovConversation(uint64(l))
l = len(m.Title)
if l > 0 {
n += 2 + l + sovConversation(uint64(l))
@@ -627,6 +641,8 @@ func (m *ConversationMember) Size() (n int) {
n += 1 + l + sovConversation(uint64(l))
l = github_com_gogo_protobuf_types.SizeOfStdTime(m.ReadAt)
n += 1 + l + sovConversation(uint64(l))
+ l = github_com_gogo_protobuf_types.SizeOfStdTime(m.WroteAt)
+ n += 1 + l + sovConversation(uint64(l))
if m.Status != 0 {
n += 1 + sovConversation(uint64(m.Status))
}
@@ -642,10 +658,6 @@ func (m *ConversationMember) Size() (n int) {
if l > 0 {
n += 2 + l + sovConversation(uint64(l))
}
- if m.Conversation != nil {
- l = m.Conversation.Size()
- n += 2 + l + sovConversation(uint64(l))
- }
if m.XXX_unrecognized != nil {
n += len(m.XXX_unrecognized)
}
@@ -813,6 +825,36 @@ func (m *Conversation) Unmarshal(dAtA []byte) error {
return err
}
iNdEx = postIndex
+ case 5:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field WroteAt", wireType)
+ }
+ var msglen int
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowConversation
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ msglen |= (int(b) & 0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ if msglen < 0 {
+ return ErrInvalidLengthConversation
+ }
+ postIndex := iNdEx + msglen
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.WroteAt, dAtA[iNdEx:postIndex]); err != nil {
+ return err
+ }
+ iNdEx = postIndex
case 20:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Title", wireType)
@@ -1120,6 +1162,36 @@ func (m *ConversationMember) Unmarshal(dAtA []byte) error {
return err
}
iNdEx = postIndex
+ case 5:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field WroteAt", wireType)
+ }
+ var msglen int
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowConversation
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ msglen |= (int(b) & 0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ if msglen < 0 {
+ return ErrInvalidLengthConversation
+ }
+ postIndex := iNdEx + msglen
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.WroteAt, dAtA[iNdEx:postIndex]); err != nil {
+ return err
+ }
+ iNdEx = postIndex
case 10:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Status", wireType)
@@ -1230,39 +1302,6 @@ func (m *ConversationMember) Unmarshal(dAtA []byte) error {
}
m.ContactID = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
- case 103:
- if wireType != 2 {
- return fmt.Errorf("proto: wrong wireType = %d for field Conversation", wireType)
- }
- var msglen int
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- return ErrIntOverflowConversation
- }
- if iNdEx >= l {
- return io.ErrUnexpectedEOF
- }
- b := dAtA[iNdEx]
- iNdEx++
- msglen |= (int(b) & 0x7F) << shift
- if b < 0x80 {
- break
- }
- }
- if msglen < 0 {
- return ErrInvalidLengthConversation
- }
- postIndex := iNdEx + msglen
- if postIndex > l {
- return io.ErrUnexpectedEOF
- }
- if m.Conversation == nil {
- m.Conversation = &Conversation{}
- }
- if err := m.Conversation.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
- return err
- }
- iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipConversation(dAtA[iNdEx:])
diff --git a/core/entity/conversation.proto b/core/entity/conversation.proto
index fa5b35cb02..bfba4bd4a0 100644
--- a/core/entity/conversation.proto
+++ b/core/entity/conversation.proto
@@ -22,6 +22,7 @@ message Conversation {
google.protobuf.Timestamp created_at = 2 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false];
google.protobuf.Timestamp updated_at = 3 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false];
google.protobuf.Timestamp read_at = 4 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false];
+ google.protobuf.Timestamp wrote_at = 5 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false];
//
// metadata
@@ -38,7 +39,7 @@ message Conversation {
//
repeated ConversationMember members = 100 [
- (gogoproto.moretags) = "gorm:\"foreignkey:ConversationID;association_foreignkey:ID\""
+ (gogoproto.moretags) = "gorm:\"foreignkey:ConversationID;association_foreignkey:ID;save_associations:true\""
]; // HasMany to ConversationMember.Conversation
enum Kind {
@@ -57,6 +58,7 @@ message ConversationMember {
google.protobuf.Timestamp created_at = 2 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false];
google.protobuf.Timestamp updated_at = 3 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false];
google.protobuf.Timestamp read_at = 4 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false];
+ google.protobuf.Timestamp wrote_at = 5 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false];
enum Status {
Unknown = 0;
@@ -78,6 +80,7 @@ message ConversationMember {
//
Contact contact = 100 [
+ (gogoproto.moretags) = "gorm:\"association_autoupdate:false;association_create:true\"",
(validate.required) = true,
(validate.skip) = false
];
@@ -93,9 +96,4 @@ message ConversationMember {
(validate.min_len) = 1,
(gql.graphql_id) = true
];
-
- Conversation conversation = 103 [
- (gogoproto.moretags) = "gorm:\"PRELOAD:false;foreignkey:ID;association_foreignkey:ConversationID\"",
- (gql.graphql_unexported) = true
- ];
}
diff --git a/core/entity/conversation.validate.gen.go b/core/entity/conversation.validate.gen.go
index 475ed8059c..5f9707120f 100644
--- a/core/entity/conversation.validate.gen.go
+++ b/core/entity/conversation.validate.gen.go
@@ -46,6 +46,14 @@ func (m *Conversation) Validate() error {
}
}
+ // handling field: WroteAt - name:"wrote_at" number:5 label:LABEL_OPTIONAL type:TYPE_MESSAGE type_name:".google.protobuf.Timestamp" json_name:"wroteAt" options:<65001:0 65010:1 > (is_contact_key=false, defined_only=false, min_len=0, max_len=0, skip=false, required=false, min_items=0, max_items=0)
+
+ if v, ok := interface{}(m.GetWroteAt()).(interface{ Validate() error }); ok {
+ if err := v.Validate(); err != nil {
+ return errors.Wrap(err, "embedded message verification failed: WroteAt")
+ }
+ }
+
// handling field: Title - name:"title" number:20 label:LABEL_OPTIONAL type:TYPE_STRING json_name:"title" (is_contact_key=false, defined_only=false, min_len=0, max_len=0, skip=false, required=false, min_items=0, max_items=0)
// handling field: Topic - name:"topic" number:21 label:LABEL_OPTIONAL type:TYPE_STRING json_name:"topic" (is_contact_key=false, defined_only=false, min_len=0, max_len=0, skip=false, required=false, min_items=0, max_items=0)
@@ -54,7 +62,7 @@ func (m *Conversation) Validate() error {
// handling field: Kind - name:"kind" number:23 label:LABEL_OPTIONAL type:TYPE_ENUM type_name:".berty.entity.Conversation.Kind" json_name:"kind" (is_contact_key=false, defined_only=false, min_len=0, max_len=0, skip=false, required=false, min_items=0, max_items=0)
- // handling field: Members - name:"members" number:100 label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".berty.entity.ConversationMember" json_name:"members" options:<65006:"gorm:\"foreignkey:ConversationID;association_foreignkey:ID\"" > (is_contact_key=false, defined_only=false, min_len=0, max_len=0, skip=false, required=false, min_items=0, max_items=0)
+ // handling field: Members - name:"members" number:100 label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".berty.entity.ConversationMember" json_name:"members" options:<65006:"gorm:\"foreignkey:ConversationID;association_foreignkey:ID;save_associations:true\"" > (is_contact_key=false, defined_only=false, min_len=0, max_len=0, skip=false, required=false, min_items=0, max_items=0)
if v, ok := interface{}(m.GetMembers()).(interface{ Validate() error }); ok {
if err := v.Validate(); err != nil {
@@ -95,9 +103,17 @@ func (m *ConversationMember) Validate() error {
}
}
+ // handling field: WroteAt - name:"wrote_at" number:5 label:LABEL_OPTIONAL type:TYPE_MESSAGE type_name:".google.protobuf.Timestamp" json_name:"wroteAt" options:<65001:0 65010:1 > (is_contact_key=false, defined_only=false, min_len=0, max_len=0, skip=false, required=false, min_items=0, max_items=0)
+
+ if v, ok := interface{}(m.GetWroteAt()).(interface{ Validate() error }); ok {
+ if err := v.Validate(); err != nil {
+ return errors.Wrap(err, "embedded message verification failed: WroteAt")
+ }
+ }
+
// handling field: Status - name:"status" number:10 label:LABEL_OPTIONAL type:TYPE_ENUM type_name:".berty.entity.ConversationMember.Status" json_name:"status" (is_contact_key=false, defined_only=false, min_len=0, max_len=0, skip=false, required=false, min_items=0, max_items=0)
- // handling field: Contact - name:"contact" number:100 label:LABEL_OPTIONAL type:TYPE_MESSAGE type_name:".berty.entity.Contact" json_name:"contact" options:<[]:true []:false > (is_contact_key=false, defined_only=false, min_len=0, max_len=0, skip=false, required=true, min_items=0, max_items=0)
+ // handling field: Contact - name:"contact" number:100 label:LABEL_OPTIONAL type:TYPE_MESSAGE type_name:".berty.entity.Contact" json_name:"contact" options:<[]:true []:false 65006:"gorm:\"association_autoupdate:false;association_create:true\"" > (is_contact_key=false, defined_only=false, min_len=0, max_len=0, skip=false, required=true, min_items=0, max_items=0)
if m.GetContact() == nil {
return errors.New("Contact is required")
}
@@ -111,14 +127,5 @@ func (m *ConversationMember) Validate() error {
// handling field: ConversationID - name:"conversation_id" number:101 label:LABEL_OPTIONAL type:TYPE_STRING json_name:"conversationId" options:<53004:1 (is_contact_key=false, defined_only=false, min_len=0, max_len=0, skip=false, required=false, min_items=0, max_items=0)
// handling field: ContactID - name:"contact_id" number:102 label:LABEL_OPTIONAL type:TYPE_STRING json_name:"contactId" options:<53004:1 (is_contact_key=false, defined_only=false, min_len=0, max_len=0, skip=false, required=false, min_items=0, max_items=0)
-
- // handling field: Conversation - name:"conversation" number:103 label:LABEL_OPTIONAL type:TYPE_MESSAGE type_name:".berty.entity.Conversation" json_name:"conversation" options:<53011:1 65006:"gorm:\"PRELOAD:false;foreignkey:ID;association_foreignkey:ConversationID\"" > (is_contact_key=false, defined_only=false, min_len=0, max_len=0, skip=false, required=false, min_items=0, max_items=0)
-
- if v, ok := interface{}(m.GetConversation()).(interface{ Validate() error }); ok {
- if err := v.Validate(); err != nil {
- return errors.Wrap(err, "embedded message verification failed: Conversation")
- }
- }
-
return nil
}
diff --git a/core/entity/conversation_test.go b/core/entity/conversation_test.go
index 72e3d120c5..add750279a 100644
--- a/core/entity/conversation_test.go
+++ b/core/entity/conversation_test.go
@@ -21,24 +21,22 @@ func Test(t *testing.T) {
bart = &Contact{ID: "bart", DisplayName: "bart", Status: Contact_IsRequested}
lisa = &Contact{ID: "lisa", DisplayName: "lisa", Status: Contact_RequestedMe}
- c *Conversation
+ c ConversationInteractor
- active ConversationMemberInteractive
-
- mm ConversationMemberInformative
- hm ConversationMemberInformative
- bm ConversationMemberInformative
- lm ConversationMemberInformative
+ mm ConversationMemberInteractor
+ hm ConversationMemberInteractor
+ bm ConversationMemberInteractor
+ lm ConversationMemberInteractor
)
Convey("create 1to1 conversation between myself and homer", t, FailureHalts, func() {
c, err = NewOneToOneConversation(myself, homer)
So(err, ShouldBeNil)
- mm, err = c.GetInteractiveMember(myself.ID)
+ mm, err = c.GetMember(myself.ID)
So(err, ShouldBeNil)
- hm, err = c.GetInteractiveMember(homer.ID)
+ hm, err = c.GetMember(homer.ID)
So(err, ShouldBeNil)
Convey("myself and homer are owners", FailureHalts, func() {
@@ -47,25 +45,16 @@ func Test(t *testing.T) {
})
Convey("myself try to block homer", FailureHalts, func() {
- active, err = c.GetInteractiveMember(mm.GetContactID())
- So(err, ShouldBeNil)
-
- err = active.Block(homer.ID)
+ err = mm.Block(homer.ID)
So(err, ShouldNotBeNil)
})
Convey("homer write a message", FailureHalts, func() {
- active, err = c.GetInteractiveMember(hm.GetContactID())
- So(err, ShouldBeNil)
-
- err = active.Write(&Message{Text: "D'oh!"})
+ err = hm.Write(time.Now(), &Message{Text: "D'oh!"})
So(err, ShouldBeNil)
Convey("myself read the message", FailureHalts, func() {
- active, err := c.GetInteractiveMember(mm.GetContactID())
- So(err, ShouldBeNil)
-
- err = active.Read(time.Now())
+ err = mm.Read(time.Now())
So(err, ShouldBeNil)
})
})
@@ -107,84 +96,55 @@ func Test(t *testing.T) {
})
Convey("bart invite homer", FailureHalts, func() {
- active, err = c.GetInteractiveMember(bm.GetContactID())
- So(err, ShouldBeNil)
-
- err = active.Invite(homer)
+ err = bm.Invite(homer)
So(err, ShouldBeNil)
hm, err = c.GetMember(homer.ID)
So(err, ShouldBeNil)
Convey("homer write message", FailureHalts, func() {
- active, err = c.GetInteractiveMember(hm.GetContactID())
- So(err, ShouldBeNil)
-
- err = active.Write(&Message{Text: "D'oh!"})
+ err = hm.Write(time.Now(), &Message{Text: "D'oh!"})
So(err, ShouldBeNil)
})
Convey("bart write message", FailureHalts, func() {
- active, err = c.GetInteractiveMember(bm.GetContactID())
- So(err, ShouldBeNil)
-
- err = active.Write(&Message{Text: "¡ Ay, caramba!"})
+ err = bm.Write(time.Now(), &Message{Text: "¡ Ay, caramba!"})
So(err, ShouldBeNil)
})
Convey("myself block homer", FailureHalts, func() {
- active, err = c.GetInteractiveMember(mm.GetContactID())
- So(err, ShouldBeNil)
-
- err = active.Block(homer.ID)
+ err = mm.Block(homer.ID)
So(err, ShouldBeNil)
Convey("homer try to write a message", FailureHalts, func() {
- active, err = c.GetInteractiveMember(hm.GetContactID())
- So(err, ShouldBeNil)
-
- err = active.Write(&Message{Text: "D'oh!"})
+ err = hm.Write(time.Now(), &Message{Text: "D'oh!"})
So(err, ShouldNotBeNil)
})
Convey("bart try to unblock homer", FailureHalts, func() {
- active, err = c.GetInteractiveMember(bm.GetContactID())
- So(err, ShouldBeNil)
-
- err = active.Unblock(homer.ID)
+ err = bm.Unblock(homer.ID)
So(err, ShouldNotBeNil)
})
Convey("bart try to block myself", FailureHalts, func() {
- active, err = c.GetInteractiveMember(bm.GetContactID())
- So(err, ShouldBeNil)
-
- err = active.Block(myself.ID)
+ err = bm.Block(myself.ID)
So(err, ShouldNotBeNil)
})
Convey("bart try to set lisa as owner", FailureHalts, func() {
- active, err = c.GetInteractiveMember(bm.GetContactID())
- So(err, ShouldBeNil)
-
- err = active.SetOwner(lisa.ID)
+ err = bm.SetOwner(lisa.ID)
So(err, ShouldNotBeNil)
})
Convey("myself set lisa as owner", FailureHalts, func() {
- active, err = c.GetInteractiveMember(mm.GetContactID())
- So(err, ShouldBeNil)
+ err = mm.SetOwner(lisa.ID)
- err = active.SetOwner(lisa.ID)
So(err, ShouldBeNil)
So(lm.IsOwner(), ShouldBeTrue)
Convey("lisa unblock homer", FailureHalts, func() {
- active, err = c.GetInteractiveMember(lm.GetContactID())
- So(err, ShouldBeNil)
-
- err = active.Unblock(homer.ID)
+ err = lm.Unblock(homer.ID)
So(err, ShouldBeNil)
})
})
diff --git a/core/node/event_handlers.go b/core/node/event_handlers.go
index 2c9afa98dc..ecb9d1f25f 100644
--- a/core/node/event_handlers.go
+++ b/core/node/event_handlers.go
@@ -141,25 +141,31 @@ func (n *Node) handleConversationUpdate(ctx context.Context, input *entity.Event
sql := n.sql(ctx)
- update := attrs.Conversation
+ // find conversation
+ conversation := &entity.Conversation{ID: attrs.Conversation.ID}
+ if err = sql.Find(&conversation).Error; err != nil {
+ return err
+ }
- cm := &entity.ConversationMember{
- ContactID: input.SourceContactID,
- ConversationID: attrs.Conversation.ID,
+ // get interactive member
+ cm, err := conversation.GetMember(input.SourceContactID)
+ if err != nil {
+ return errorcodes.ErrNodeHandleConversationUpdate.Wrap(err)
}
+
if err := sql.Preload("Conversation").First(cm).Error; err != nil {
return bsql.GenericError(err)
}
- if err := cm.SetTitle(update.Title); err != nil {
+ if err := cm.SetTitle(attrs.Conversation.Title); err != nil {
return errorcodes.ErrNodeHandleConversationUpdate.Wrap(err)
}
- if err := cm.SetTopic(update.Title); err != nil {
+ if err := cm.SetTopic(attrs.Conversation.Title); err != nil {
return errorcodes.ErrNodeHandleConversationUpdate.Wrap(err)
}
- if err := bsql.ConversationSave(sql, cm.Conversation); err != nil {
+ if err := bsql.ConversationSave(sql, conversation); err != nil {
return errorcodes.ErrNodeHandleConversationUpdate.Wrap(err)
}
@@ -228,14 +234,14 @@ func (n *Node) handleConversationNewMessage(ctx context.Context, input *entity.E
}
// get interactive member
- im, err := conversation.GetInteractiveMember(input.SourceContactID)
+ im, err := conversation.GetMember(input.SourceContactID)
if err != nil {
n.LogBackgroundWarn(ctx, errors.New("handleConversationNewMessage: Member not found"))
return err
}
// say that member have write to conversation
- if err = im.Write(attrs.Message); err != nil {
+ if err = im.Write(input.CreatedAt, attrs.Message); err != nil {
return err
}
@@ -290,7 +296,7 @@ func (n *Node) handleConversationRead(ctx context.Context, input *entity.Event)
}
// get interactive member
- im, err := conversation.GetInteractiveMember(input.SourceContactID)
+ im, err := conversation.GetMember(input.SourceContactID)
if err != nil {
return err
}
diff --git a/core/node/nodeapi.go b/core/node/nodeapi.go
index 0c50b76826..61c8ceffec 100644
--- a/core/node/nodeapi.go
+++ b/core/node/nodeapi.go
@@ -134,10 +134,10 @@ func (n *Node) EventSeen(ctx context.Context, input *entity.Event) (*entity.Even
return nil, errorcodes.ErrDbUpdate.Wrap(err)
}
- // check if event is from another contact
- if event.Direction != entity.Event_Incoming {
- return event, nil
- }
+ // // check if event is from another contact
+ // if event.Direction != entity.Event_Incoming {
+ // return event, nil
+ // }
seenAt := time.Now().UTC()
event.SeenAt = &seenAt
@@ -147,14 +147,6 @@ func (n *Node) EventSeen(ctx context.Context, input *entity.Event) (*entity.Even
return nil, errors.Wrap(err, "cannot set event as seen")
}
- // mark conversation as read
- if event.TargetType == entity.Event_ToSpecificConversation {
- _, err := n.ConversationRead(ctx, &entity.Conversation{ID: event.ToConversationID()})
- if err != nil {
- return nil, err
- }
- }
-
return event, nil
}
@@ -258,7 +250,7 @@ func (n *Node) ContactRequest(ctx context.Context, req *node.ContactRequestInput
} else if contact.Status == entity.Contact_Myself {
return nil, errorcodes.ErrContactReqMyself.New()
- } else {
+ } else if contact.Status != entity.Contact_Unknown {
return nil, errorcodes.ErrContactReqExisting.New()
}
@@ -365,14 +357,9 @@ func (n *Node) ContactRemove(ctx context.Context, contact *entity.Contact) (*ent
return nil, errorcodes.ErrDbDelete.Wrap(err)
}
- // remove 1-1 conversation
- // don't return error if not found
- conversation, err := bsql.ConversationOneToOne(sql, n.config.Myself.ID, contact.ID)
- switch {
- case err == nil: // conversation exists, delete it
- n.ConversationRemove(ctx, &entity.Conversation{ID: conversation.ID})
- case gorm.IsRecordNotFoundError(errors.Cause(err)): // conversation is not found, do nothing
- case err != nil: // another error is triggered, returning it
+ // remove one to one conversation
+ _, err = n.conversationRemove(ctx, &entity.Conversation{ID: entity.GetOneToOneID(n.config.Myself, contact)})
+ if err != nil {
return nil, err
}
diff --git a/core/node/nodeapi_conversation.go b/core/node/nodeapi_conversation.go
index 13e5c05e45..c2b06bbd61 100644
--- a/core/node/nodeapi_conversation.go
+++ b/core/node/nodeapi_conversation.go
@@ -117,7 +117,7 @@ func (n *Node) ConversationInvite(ctx context.Context, input *node.ConversationM
}
// find interactive member (current node user)
- cm, err := c.GetInteractiveMember(n.UserID())
+ cm, err := c.GetMember(n.UserID())
if err != nil {
return nil, err
}
@@ -228,13 +228,13 @@ func (n *Node) ConversationAddMessage(ctx context.Context, input *node.Conversat
}
// get interactive member (current user)
- im, err := conversation.GetInteractiveMember(n.UserID())
+ im, err := conversation.GetMember(n.UserID())
if err != nil {
return nil, err
}
// member write new message
- if err = im.Write(input.Message); err != nil {
+ if err = im.Write(time.Now().UTC(), input.Message); err != nil {
return nil, err
}
@@ -301,7 +301,7 @@ func (n *Node) ConversationUpdate(ctx context.Context, input *entity.Conversatio
}
// get interactive member (current user)
- im, err := conversation.GetInteractiveMember(n.UserID())
+ im, err := conversation.GetMember(n.UserID())
if err != nil {
return nil, err
}
@@ -339,7 +339,7 @@ func (n *Node) ConversationRead(ctx context.Context, input *entity.Conversation)
}
// get interactive member (current user)
- im, err := conversation.GetInteractiveMember(n.UserID())
+ im, err := conversation.GetMember(n.UserID())
if err != nil {
return nil, err
}
@@ -370,7 +370,7 @@ func (n *Node) ConversationRead(ctx context.Context, input *entity.Conversation)
return conversation, n.EnqueueOutgoingEvent(ctx,
n.NewEvent(ctx).
SetToConversation(conversation).
- SetConversationReadAttrs(&entity.ConversationReadAttrs{Conversation: conversation}))
+ SetConversationReadAttrs(&entity.ConversationReadAttrs{Conversation: conversation.Filtered()}))
}
func (n *Node) ConversationLastEvent(ctx context.Context, input *entity.Conversation) (*entity.Event, error) {
@@ -389,24 +389,37 @@ func (n *Node) ConversationLastEvent(ctx context.Context, input *entity.Conversa
}
func (n *Node) ConversationRemove(ctx context.Context, input *entity.Conversation) (*entity.Conversation, error) {
+ defer n.handleMutex(ctx)()
+
+ return n.conversationRemove(ctx, input)
+}
+
+func (n *Node) conversationRemove(ctx context.Context, input *entity.Conversation) (*entity.Conversation, error) {
var err error
+ sql := n.sql(ctx)
+
// get conversation
- if err = n.sql(ctx).First(input).Error; err != nil {
- return nil, bsql.GenericError(err)
+ conversation := &entity.Conversation{ID: input.ID}
+ if err = sql.Model(conversation).Where(conversation).First(conversation).Error; err != nil {
+ return nil, err
}
- // remove conversation
- sql := n.sql(ctx)
- if err = sql.
- Where(&entity.ConversationMember{ConversationID: input.ID}).
- Delete(&entity.ConversationMember{}).Error; err != nil {
- return nil, errorcodes.ErrDbDelete.Wrap(err)
+ // remove conversation before all
+ if err = sql.Delete(conversation).Error; err != nil {
+ return nil, err
}
- if err = sql.Delete(input).Error; err != nil {
- return nil, errorcodes.ErrDbDelete.Wrap(err)
+ // get interactive member (current user)
+ im, err := conversation.GetMember(n.UserID())
+ if err != nil {
+ return nil, err
}
- return input, nil
+ // leave conversation
+ if err = im.Leave(); err != nil {
+ return nil, err
+ }
+
+ return conversation, nil
}
diff --git a/core/node/sql.go b/core/node/sql.go
index ba71b732ef..51bcfc5137 100644
--- a/core/node/sql.go
+++ b/core/node/sql.go
@@ -123,12 +123,6 @@ func (n *Node) createCommitLog(scope *gorm.Scope, operation string, reflectValue
case *entity.Config:
log.Entity = &node.CommitLog_Entity{Config: data}
case *entity.Event:
- if operation != "delete" {
- data, err = sql.EventByID(scope.DB(), data.ID)
- if err != nil {
- return nil
- }
- }
log.Entity = &node.CommitLog_Entity{Event: data}
case *entity.DevicePushConfig:
log.Entity = &node.CommitLog_Entity{DevicePushConfig: data}
diff --git a/core/pkg/errorcodes/errors.pb.go b/core/pkg/errorcodes/errors.pb.go
index 21fa16e907..218c8bf5cb 100644
--- a/core/pkg/errorcodes/errors.pb.go
+++ b/core/pkg/errorcodes/errors.pb.go
@@ -118,7 +118,6 @@ const (
ErrConversationIsMember Code = 13204
ErrConversationGetMember Code = 13205
ErrConversationGetOwners Code = 13206
- ErrConversationGetInteractiveMember Code = 13207
ErrConversationMember Code = 13500
ErrConversationMemberID Code = 13501
ErrConversationMemberStatus Code = 13502
@@ -266,7 +265,6 @@ var Code_name = map[int32]string{
13204: "ErrConversationIsMember",
13205: "ErrConversationGetMember",
13206: "ErrConversationGetOwners",
- 13207: "ErrConversationGetInteractiveMember",
13500: "ErrConversationMember",
13501: "ErrConversationMemberID",
13502: "ErrConversationMemberStatus",
@@ -414,7 +412,6 @@ var Code_value = map[string]int32{
"ErrConversationIsMember": 13204,
"ErrConversationGetMember": 13205,
"ErrConversationGetOwners": 13206,
- "ErrConversationGetInteractiveMember": 13207,
"ErrConversationMember": 13500,
"ErrConversationMemberID": 13501,
"ErrConversationMemberStatus": 13502,
@@ -581,129 +578,128 @@ func init() {
func init() { proto.RegisterFile("pkg/errorcodes/errors.proto", fileDescriptor_f04d618bf87de955) }
var fileDescriptor_f04d618bf87de955 = []byte{
- // 1955 bytes of a gzipped FileDescriptorProto
- 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x58, 0x6b, 0x8c, 0x5b, 0x47,
- 0xf5, 0xcf, 0xdd, 0x24, 0xbb, 0xc9, 0xe4, 0xb1, 0x27, 0x93, 0x64, 0xd7, 0xdd, 0x24, 0xbb, 0xdb,
- 0xf6, 0xff, 0x27, 0x51, 0x05, 0x1b, 0x14, 0xa4, 0x08, 0x21, 0x41, 0xba, 0xf6, 0xb5, 0x8d, 0x95,
- 0xae, 0xe3, 0xae, 0xb3, 0x20, 0x21, 0x45, 0x68, 0x7c, 0xef, 0xd9, 0xeb, 0xd1, 0x5e, 0xcf, 0x35,
- 0x73, 0xe7, 0xba, 0x31, 0x52, 0x25, 0xa8, 0x0c, 0xa4, 0xa5, 0x45, 0x4d, 0x5f, 0x14, 0x68, 0xcb,
- 0x1b, 0xf1, 0x28, 0xef, 0x02, 0x2d, 0x34, 0xa5, 0xf0, 0xa9, 0x3c, 0x95, 0x96, 0x2f, 0x3c, 0xa5,
- 0x92, 0x7e, 0x69, 0x4b, 0x29, 0x69, 0x01, 0x89, 0xc7, 0x17, 0x34, 0xf7, 0x8e, 0xed, 0xeb, 0xb5,
- 0x77, 0x3f, 0xad, 0xe7, 0xf7, 0x3b, 0x73, 0xce, 0x6f, 0xce, 0x9c, 0x39, 0x33, 0x77, 0xc9, 0xa1,
- 0xe6, 0x9a, 0x77, 0x1c, 0xa5, 0x0c, 0xa4, 0x13, 0xb8, 0x18, 0x26, 0x3f, 0xc3, 0x85, 0xa6, 0x0c,
- 0x54, 0x40, 0xa1, 0x86, 0x52, 0xb5, 0x17, 0xfa, 0xf4, 0xcc, 0x9b, 0x3c, 0xae, 0xea, 0x51, 0x6d,
- 0xc1, 0x09, 0x1a, 0xc7, 0xbd, 0xc0, 0x0b, 0x8e, 0xc7, 0x86, 0xb5, 0x68, 0x35, 0x1e, 0xc5, 0x83,
- 0xf8, 0x57, 0xe2, 0xe0, 0xba, 0x57, 0xc7, 0xc8, 0x8e, 0x25, 0x54, 0xcc, 0x65, 0x8a, 0xd1, 0x1b,
- 0xc8, 0x36, 0xed, 0x24, 0x63, 0xcd, 0x5b, 0xc7, 0xf6, 0x9e, 0x98, 0x5a, 0x58, 0xef, 0x7c, 0x21,
- 0x17, 0xb8, 0xb8, 0x1c, 0xdb, 0xd0, 0xb7, 0x93, 0xbd, 0x78, 0x5e, 0xa1, 0x70, 0xd1, 0x7d, 0x6f,
- 0x4c, 0x66, 0xc6, 0xe6, 0xb7, 0x6e, 0x32, 0x6b, 0x4f, 0xd7, 0x5a, 0x8f, 0x42, 0x5a, 0x21, 0xbb,
- 0x9b, 0x3e, 0x73, 0xb0, 0x1e, 0xf8, 0x2e, 0xca, 0x30, 0xb3, 0x75, 0x7e, 0xeb, 0xb1, 0x5d, 0x27,
- 0xde, 0x38, 0x3c, 0xb9, 0x2b, 0x6e, 0xa1, 0x92, 0x32, 0xcf, 0x0b, 0x25, 0xdb, 0xcb, 0x03, 0x1e,
- 0xe8, 0x09, 0x32, 0xde, 0x64, 0x12, 0x85, 0xca, 0x6c, 0x9b, 0xb7, 0x8e, 0xed, 0x3a, 0x31, 0xb3,
- 0xb1, 0xaf, 0x65, 0x63, 0x49, 0x33, 0x64, 0xa2, 0x81, 0x61, 0xc8, 0x3c, 0xcc, 0x6c, 0x9f, 0xb7,
- 0x8e, 0xed, 0x5c, 0xee, 0x0e, 0xe9, 0x14, 0x19, 0x77, 0x98, 0xef, 0xa3, 0xcc, 0x8c, 0xc7, 0x84,
- 0x19, 0xcd, 0x9c, 0x22, 0xfb, 0x86, 0x84, 0x50, 0x20, 0x5b, 0xd7, 0xb0, 0x1d, 0xa7, 0x6d, 0xe7,
- 0xb2, 0xfe, 0x49, 0x0f, 0x90, 0xed, 0x2d, 0xe6, 0x47, 0x98, 0x19, 0x8b, 0xb1, 0x64, 0xf0, 0xb6,
- 0xb1, 0xb7, 0x5a, 0x37, 0x3c, 0x7a, 0x84, 0x6c, 0xd3, 0x29, 0xa0, 0x40, 0x76, 0xe7, 0xa5, 0x5c,
- 0x11, 0x2e, 0xae, 0x72, 0x81, 0x2e, 0x6c, 0xa1, 0xe3, 0x64, 0xec, 0xcc, 0x69, 0xb0, 0xe8, 0x2e,
- 0x32, 0x91, 0x97, 0x32, 0xcb, 0x42, 0x84, 0x31, 0x7a, 0x80, 0x40, 0x6c, 0xc6, 0x1b, 0x4d, 0x1f,
- 0x1b, 0x28, 0x14, 0xba, 0xb0, 0x95, 0x1e, 0x26, 0x99, 0xbc, 0x94, 0xcb, 0x4c, 0xb8, 0x41, 0xa3,
- 0x88, 0x02, 0x25, 0x53, 0x81, 0x2c, 0x30, 0xee, 0xa3, 0x0b, 0xdb, 0xe8, 0x0c, 0x99, 0xd2, 0x73,
- 0x56, 0x4a, 0xf6, 0x7a, 0x6e, 0xbb, 0xf1, 0x57, 0x45, 0xc9, 0x99, 0xcf, 0xdf, 0xcf, 0x14, 0x0f,
- 0x04, 0x8c, 0xd3, 0x29, 0x42, 0xf3, 0x52, 0xda, 0x18, 0x0e, 0xe0, 0x13, 0x74, 0x37, 0xd9, 0x91,
- 0x97, 0xb2, 0xc2, 0x04, 0x77, 0x60, 0x07, 0x05, 0xb2, 0x2b, 0x2f, 0x65, 0x5e, 0xb4, 0xd0, 0x0f,
- 0x9a, 0x08, 0x2f, 0x4e, 0xd0, 0x6b, 0xc8, 0x81, 0x14, 0xb2, 0x22, 0x94, 0x8c, 0x42, 0xad, 0xf0,
- 0xa5, 0x09, 0x7a, 0x24, 0x96, 0xd8, 0xa5, 0xca, 0x81, 0x8d, 0x2d, 0xee, 0x60, 0x21, 0x88, 0x84,
- 0x0b, 0x2f, 0x4f, 0xd0, 0xbd, 0x64, 0x67, 0x4c, 0x2b, 0xae, 0xda, 0x70, 0x79, 0x92, 0xee, 0x27,
- 0x7b, 0x7b, 0xe3, 0x92, 0x68, 0x46, 0x0a, 0x9e, 0x9d, 0xa4, 0x94, 0xec, 0xe9, 0x81, 0x36, 0x53,
- 0x0c, 0x9e, 0x9b, 0xa4, 0x07, 0xc8, 0x64, 0x0f, 0xcb, 0x9f, 0xe7, 0xa1, 0x0a, 0xe1, 0x37, 0x93,
- 0x74, 0x17, 0x19, 0xcf, 0x4b, 0x59, 0x46, 0x05, 0x8f, 0x4f, 0xd3, 0x6b, 0xc9, 0xe1, 0x64, 0xb0,
- 0x28, 0x02, 0x55, 0x47, 0x99, 0xf3, 0x39, 0x0a, 0x95, 0x0b, 0x84, 0x40, 0x47, 0xab, 0x7b, 0x62,
- 0x9a, 0xee, 0x8b, 0xb3, 0x5f, 0x46, 0x55, 0x55, 0x12, 0x59, 0x03, 0x7e, 0x38, 0x6d, 0x56, 0x57,
- 0x46, 0x75, 0x73, 0x84, 0x11, 0xc2, 0x8f, 0xa6, 0xe9, 0x24, 0x21, 0x09, 0x62, 0x73, 0xe6, 0xc3,
- 0x93, 0x29, 0xa0, 0xc2, 0x85, 0x07, 0x97, 0xa6, 0xcd, 0x2a, 0x34, 0x70, 0xa2, 0x02, 0x0f, 0x65,
- 0xe8, 0x14, 0xd9, 0xd7, 0x1b, 0x97, 0x5c, 0x4c, 0x56, 0xf7, 0x70, 0x86, 0x4e, 0xc7, 0xf9, 0x4d,
- 0xf0, 0x4a, 0x54, 0xf3, 0xb9, 0x73, 0x1a, 0xdb, 0xf0, 0x48, 0x86, 0xee, 0x89, 0x13, 0x9c, 0x6f,
- 0xa1, 0x50, 0xf0, 0x99, 0xb9, 0x6e, 0x16, 0xf4, 0xb0, 0xaa, 0x4f, 0x8b, 0x84, 0xcf, 0xce, 0x19,
- 0xad, 0x31, 0x18, 0x27, 0xe1, 0x73, 0x73, 0x26, 0x31, 0xef, 0x62, 0x3e, 0x77, 0x93, 0xad, 0xba,
- 0x70, 0xd4, 0xc4, 0xe8, 0x63, 0x49, 0x16, 0x6f, 0x3f, 0x4a, 0x33, 0x64, 0xff, 0x00, 0xb1, 0xd4,
- 0x0e, 0xd1, 0x5f, 0x85, 0x3b, 0x8e, 0x1a, 0x37, 0x15, 0xe6, 0x71, 0x91, 0xb8, 0xb9, 0xba, 0x40,
- 0x09, 0xd9, 0xae, 0x4b, 0xa1, 0x06, 0xbf, 0x3d, 0x69, 0x52, 0x62, 0xd7, 0x72, 0x12, 0x99, 0x42,
- 0xf8, 0x5d, 0x1f, 0x59, 0x69, 0xba, 0x1a, 0xf9, 0x7d, 0x1f, 0xb1, 0xd1, 0x47, 0x85, 0xf0, 0x87,
- 0x93, 0x26, 0x09, 0x76, 0xad, 0x1c, 0xa8, 0x3a, 0x17, 0x5e, 0xb2, 0xe5, 0x7f, 0x3c, 0x69, 0x04,
- 0xda, 0xb5, 0x92, 0x50, 0x28, 0x05, 0xf3, 0xf3, 0xfa, 0x64, 0xc2, 0x9f, 0x4e, 0x9a, 0x2c, 0xe6,
- 0x64, 0xbb, 0xa9, 0x02, 0x78, 0xfa, 0x1d, 0x66, 0xc1, 0xc9, 0xb8, 0xca, 0x3d, 0xf8, 0xc2, 0x29,
- 0x53, 0x68, 0x3d, 0x68, 0x89, 0x87, 0x0d, 0xa6, 0x9c, 0x3a, 0x7c, 0xf1, 0x94, 0x71, 0xdb, 0xa3,
- 0x0a, 0x81, 0x6c, 0x30, 0x05, 0x5f, 0x3a, 0x45, 0x0f, 0xc6, 0xa5, 0x9e, 0x10, 0x79, 0xe1, 0xe8,
- 0xbf, 0x70, 0xe1, 0xc6, 0x01, 0xd8, 0xc6, 0x04, 0x7e, 0xe5, 0xc6, 0x81, 0xa0, 0x7a, 0x73, 0x2e,
- 0x2f, 0x9a, 0x52, 0xeb, 0x41, 0x45, 0x14, 0xf0, 0xec, 0xe2, 0x40, 0xbc, 0xd3, 0xd8, 0xb6, 0x51,
- 0x37, 0x17, 0x78, 0x6e, 0xd1, 0xac, 0xbb, 0x27, 0xc4, 0xa9, 0x33, 0x2e, 0xe0, 0xb1, 0xac, 0xc9,
- 0xf2, 0xa2, 0xe3, 0x2c, 0x31, 0xc1, 0x3c, 0x94, 0xf0, 0xe5, 0x02, 0x9d, 0x21, 0x07, 0x07, 0xb0,
- 0x92, 0xe0, 0xaa, 0xac, 0xfd, 0x7c, 0xa5, 0x60, 0xc2, 0xf6, 0x39, 0xbb, 0x06, 0x5f, 0x2d, 0x98,
- 0x5d, 0x4c, 0xa3, 0x7a, 0x0e, 0x7c, 0x6d, 0x14, 0x63, 0xcb, 0xa0, 0x09, 0x8f, 0x16, 0x8c, 0xd4,
- 0x34, 0xb3, 0xc4, 0x3d, 0xf8, 0xfa, 0x28, 0xc2, 0xe6, 0x12, 0xbe, 0x51, 0xa0, 0x87, 0xe2, 0xd6,
- 0xd1, 0x27, 0xca, 0x81, 0x3a, 0xd3, 0x44, 0xdd, 0x9f, 0xbe, 0x59, 0x30, 0x99, 0xeb, 0x93, 0xb9,
- 0x55, 0x0f, 0xee, 0x2c, 0x9a, 0xbd, 0x19, 0x80, 0xcb, 0xac, 0x81, 0x70, 0x57, 0x91, 0xce, 0x91,
- 0x99, 0xf5, 0x54, 0x85, 0x85, 0x61, 0xb3, 0x2e, 0x75, 0x77, 0xfb, 0x58, 0x71, 0x48, 0xbb, 0x9e,
- 0x8b, 0x0a, 0xee, 0x2e, 0xd2, 0xc3, 0x64, 0x7a, 0x3d, 0x53, 0x94, 0x4d, 0xa7, 0x2a, 0x5b, 0x70,
- 0xb1, 0x38, 0x24, 0x25, 0x1b, 0x28, 0xb8, 0x3a, 0x2c, 0x25, 0x1b, 0xa8, 0x38, 0x4b, 0xaf, 0x15,
- 0x87, 0x56, 0x96, 0x0d, 0x54, 0xfe, 0x3c, 0xd7, 0xed, 0xe0, 0xf5, 0xa2, 0xd9, 0xa2, 0x5c, 0x20,
- 0x14, 0x73, 0xd4, 0x32, 0xbe, 0x0f, 0xee, 0x2e, 0x77, 0xeb, 0xa4, 0x87, 0xe9, 0xa2, 0xb8, 0x58,
- 0x36, 0xba, 0x06, 0xe0, 0x25, 0x1e, 0x86, 0xba, 0x21, 0xdc, 0x53, 0x36, 0xfb, 0xda, 0x67, 0xe3,
- 0x0e, 0xa5, 0xb9, 0x7b, 0xcb, 0x66, 0xad, 0x7d, 0xce, 0x9c, 0xc3, 0xfb, 0xd6, 0x85, 0xba, 0x09,
- 0x85, 0xa7, 0xea, 0x70, 0x7f, 0xb9, 0x5b, 0x92, 0x09, 0x5c, 0xb2, 0xe1, 0x81, 0xb2, 0xe9, 0x73,
- 0x3a, 0xf1, 0xff, 0x5a, 0xe9, 0xaa, 0x5e, 0xf5, 0xba, 0x02, 0xfe, 0xbd, 0xd2, 0x9d, 0xb3, 0xea,
- 0x19, 0xef, 0xff, 0x49, 0x99, 0x25, 0x2d, 0x38, 0x84, 0xff, 0xae, 0x98, 0x46, 0x93, 0xf4, 0x98,
- 0x45, 0x9f, 0xb3, 0x10, 0x9e, 0x3f, 0x67, 0x0a, 0x38, 0x05, 0xea, 0x8a, 0xff, 0xf3, 0x39, 0xb3,
- 0x8b, 0x29, 0xbc, 0x1c, 0xe4, 0x98, 0x70, 0x75, 0x3b, 0xc1, 0x10, 0xae, 0x8c, 0x30, 0x48, 0xda,
- 0x83, 0xb9, 0x74, 0x5e, 0x38, 0xd7, 0x3d, 0x49, 0x81, 0x68, 0xa1, 0x0c, 0x93, 0x56, 0xf3, 0x0c,
- 0x76, 0x0f, 0x4c, 0x0a, 0x2d, 0xd9, 0xf0, 0x33, 0xec, 0x1e, 0xf6, 0x14, 0x7e, 0x96, 0x2b, 0x1f,
- 0xe1, 0xe7, 0x23, 0xa9, 0xa0, 0xc9, 0x1d, 0xf8, 0xc5, 0x28, 0xaa, 0x24, 0x56, 0x83, 0x10, 0x7e,
- 0x89, 0xfd, 0xcc, 0xf7, 0xa8, 0xd3, 0x5c, 0xb8, 0xf0, 0x2b, 0x34, 0x55, 0x91, 0x66, 0x96, 0xb0,
- 0x51, 0x43, 0x19, 0xc2, 0xaf, 0x91, 0xfe, 0x1f, 0x99, 0x1b, 0x49, 0x96, 0xc2, 0x33, 0x02, 0xcf,
- 0x06, 0x67, 0x04, 0xc2, 0x45, 0x6f, 0x84, 0x8b, 0x52, 0x58, 0x94, 0x41, 0xd4, 0x84, 0x7b, 0xbc,
- 0x7e, 0x3d, 0xa4, 0xc8, 0x42, 0xe4, 0xfb, 0x70, 0xaf, 0xd7, 0xaf, 0xa4, 0x14, 0x97, 0x04, 0x80,
- 0xfb, 0x3c, 0x73, 0x7f, 0xa6, 0xd9, 0x22, 0x2a, 0x43, 0xdf, 0xbf, 0x01, 0x7d, 0xe6, 0x16, 0xa1,
- 0xa5, 0x3f, 0xe0, 0xd1, 0x63, 0xe4, 0xfa, 0x61, 0x3a, 0x6e, 0xbc, 0xcc, 0x51, 0xbc, 0x85, 0xc6,
- 0xd1, 0xc7, 0x47, 0x29, 0x34, 0xdc, 0x93, 0x7c, 0x84, 0x42, 0x93, 0x00, 0x1b, 0x2e, 0x71, 0x3a,
- 0x4f, 0x0e, 0x8d, 0x64, 0xab, 0x8a, 0xa9, 0x28, 0x84, 0xa7, 0xb8, 0xb9, 0x88, 0x87, 0x2d, 0x4c,
- 0x49, 0xc3, 0x8f, 0x39, 0xbd, 0x9e, 0xcc, 0x6e, 0x66, 0x52, 0xb2, 0xe1, 0x69, 0x4e, 0xdf, 0x40,
- 0xae, 0xdd, 0xc8, 0xa8, 0x5f, 0x50, 0x3f, 0xe1, 0x23, 0x56, 0x3d, 0x6c, 0x57, 0xb2, 0xe1, 0xa7,
- 0x1b, 0x6b, 0x2f, 0x89, 0x16, 0x57, 0x08, 0x1f, 0x5a, 0x33, 0x35, 0x3d, 0x6c, 0x71, 0x13, 0xb2,
- 0x16, 0xc2, 0x87, 0xd7, 0xe8, 0x75, 0xe4, 0xc8, 0xe8, 0xe5, 0xa3, 0x4a, 0xca, 0xf5, 0x23, 0x9b,
- 0xdb, 0xc4, 0x75, 0x7b, 0x61, 0x53, 0x9b, 0x78, 0x3f, 0xe1, 0xf6, 0x8d, 0xc5, 0x64, 0xfd, 0xc0,
- 0x59, 0x83, 0x3b, 0xd6, 0x36, 0xcc, 0xf4, 0x8a, 0xa8, 0xc5, 0x26, 0x1f, 0x5d, 0xa3, 0xb3, 0xe4,
- 0x9a, 0x91, 0x26, 0xcb, 0xc8, 0x5c, 0xb8, 0x73, 0xe3, 0x18, 0xef, 0x96, 0x3a, 0x23, 0x77, 0xad,
- 0xd1, 0xdd, 0xf1, 0xbb, 0xb4, 0x12, 0x85, 0x75, 0xf8, 0x56, 0xc3, 0x94, 0xbd, 0x1e, 0xad, 0x88,
- 0x35, 0x11, 0xdc, 0x22, 0x2a, 0x32, 0x68, 0x71, 0xfd, 0x64, 0xf9, 0x76, 0xc3, 0x9c, 0x77, 0x4d,
- 0xf6, 0xd0, 0xef, 0x34, 0x4c, 0xcd, 0x6a, 0xb4, 0x24, 0x5a, 0xfa, 0x39, 0x92, 0x3c, 0x91, 0x56,
- 0x39, 0x4a, 0xf8, 0x6e, 0xc3, 0x08, 0x48, 0xd1, 0x55, 0x94, 0xad, 0x78, 0xf3, 0x56, 0xb9, 0x07,
- 0x8f, 0xa5, 0x43, 0x9a, 0x86, 0x97, 0x8d, 0x84, 0xeb, 0x63, 0xc9, 0x85, 0xef, 0x35, 0xcc, 0xf2,
- 0x52, 0x7a, 0x6c, 0xd4, 0x9d, 0x37, 0xa9, 0x8d, 0xef, 0xa7, 0xbd, 0x67, 0x65, 0xc0, 0x5c, 0x87,
- 0x85, 0x2a, 0x15, 0xfe, 0x07, 0x0d, 0x73, 0x27, 0xa6, 0xc2, 0x9f, 0x6d, 0x37, 0x11, 0x1e, 0x6f,
- 0x98, 0xee, 0x3c, 0x30, 0x13, 0x9e, 0xe8, 0xae, 0xb1, 0x1c, 0x68, 0x0f, 0x4e, 0x12, 0xe6, 0xc1,
- 0xc8, 0xc8, 0x48, 0xa3, 0x4b, 0x4c, 0x86, 0x75, 0xe6, 0x17, 0x72, 0x4b, 0xf0, 0x89, 0xc8, 0xc8,
- 0x18, 0xc1, 0x2f, 0x56, 0xca, 0x55, 0xf8, 0xe4, 0x26, 0x06, 0x4b, 0x37, 0x9f, 0x3d, 0x0b, 0x9f,
- 0x8a, 0x4c, 0xe9, 0xa6, 0x0d, 0x56, 0x44, 0xa3, 0x1f, 0xe3, 0xa1, 0xa8, 0xfb, 0xfe, 0x1d, 0x65,
- 0x11, 0x47, 0x79, 0x78, 0x53, 0x93, 0x38, 0xce, 0x23, 0x91, 0xc9, 0x76, 0xda, 0x64, 0x19, 0x1d,
- 0xe4, 0x2d, 0x84, 0x4f, 0x47, 0xa6, 0x16, 0xe2, 0x17, 0xcb, 0x07, 0x6e, 0x35, 0xfd, 0x55, 0x8f,
- 0x74, 0x96, 0xe2, 0x29, 0xd5, 0xa8, 0x06, 0x1f, 0xbc, 0x95, 0xfe, 0x7f, 0xdc, 0x42, 0x35, 0xf3,
- 0x4e, 0xa6, 0xf7, 0x2a, 0x5d, 0x5e, 0xe6, 0x0d, 0x79, 0xe9, 0x36, 0x6b, 0x53, 0x33, 0x73, 0x24,
- 0x9f, 0xba, 0xcd, 0xa2, 0x7b, 0xe3, 0xd7, 0x72, 0xae, 0x1e, 0x89, 0x35, 0x78, 0xb1, 0x63, 0xd1,
- 0xa9, 0xe4, 0xde, 0xd4, 0xe3, 0x2c, 0x73, 0x4b, 0xc2, 0xc5, 0xf3, 0xf0, 0x52, 0xc7, 0xa2, 0x07,
- 0x93, 0xeb, 0xc6, 0xe0, 0xf1, 0xa3, 0xf9, 0xe5, 0x8e, 0x45, 0x33, 0xc9, 0xcb, 0xcd, 0xc0, 0x55,
- 0x9f, 0x3b, 0x58, 0xb2, 0xe1, 0x2f, 0x1d, 0x8b, 0x1e, 0x4e, 0x7a, 0x78, 0x9a, 0x31, 0xd7, 0xf0,
- 0x2b, 0x1d, 0x8b, 0xce, 0x26, 0xbd, 0x56, 0xb3, 0x31, 0x55, 0x0e, 0x54, 0x2e, 0xd0, 0xdf, 0x63,
- 0x0a, 0xe1, 0xaf, 0x43, 0x32, 0x62, 0x13, 0x78, 0xb5, 0x63, 0xd1, 0xb9, 0xe4, 0xc4, 0x69, 0xdc,
- 0x66, 0xd8, 0x08, 0x44, 0x55, 0x05, 0x92, 0x79, 0x58, 0x61, 0xaa, 0x0e, 0x7f, 0xeb, 0x58, 0x74,
- 0x3e, 0x39, 0x72, 0x7d, 0x03, 0xfd, 0xd6, 0xd2, 0x72, 0x6b, 0xfa, 0x79, 0x74, 0xb5, 0x63, 0xd1,
- 0xfd, 0xc9, 0xdd, 0xdd, 0x0b, 0x0d, 0xaf, 0x0d, 0x2e, 0x2f, 0xfe, 0x98, 0x08, 0xeb, 0xf0, 0x7a,
- 0xc7, 0xa2, 0x34, 0xb9, 0xfa, 0x63, 0x5b, 0xdd, 0xa3, 0xfe, 0xde, 0xb1, 0xe8, 0xa1, 0xa4, 0xbb,
- 0x6b, 0xac, 0xc0, 0x45, 0xa2, 0x2d, 0xdb, 0x2e, 0xd9, 0xf0, 0x8f, 0x61, 0x72, 0xd1, 0xf7, 0x63,
- 0x3e, 0x84, 0x7f, 0x76, 0xac, 0x99, 0x6d, 0x17, 0x3e, 0x3f, 0xbb, 0x25, 0xfb, 0xe6, 0x67, 0xae,
- 0xcc, 0x5a, 0x97, 0xaf, 0xcc, 0x5a, 0xcf, 0x5f, 0x99, 0xb5, 0x1e, 0x7c, 0x61, 0x76, 0xcb, 0x7b,
- 0x66, 0x93, 0xcf, 0x6a, 0x85, 0x4e, 0xfd, 0xb8, 0x13, 0x48, 0x3c, 0x3e, 0xf8, 0xff, 0x89, 0xda,
- 0x78, 0xfc, 0x8f, 0x85, 0xb7, 0xfc, 0x2f, 0x00, 0x00, 0xff, 0xff, 0x00, 0x49, 0x59, 0x2e, 0xb8,
+ // 1939 bytes of a gzipped FileDescriptorProto
+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x58, 0x6b, 0x6c, 0x5c, 0x47,
+ 0x15, 0xee, 0x75, 0x12, 0x3b, 0x99, 0x3c, 0x7c, 0x32, 0x49, 0xec, 0xad, 0x93, 0xd8, 0x6e, 0x0b,
+ 0x24, 0xaa, 0xc0, 0x41, 0x41, 0x8a, 0x10, 0x12, 0xa4, 0xde, 0xbd, 0xbb, 0xcb, 0x2a, 0xf5, 0x66,
+ 0xeb, 0x8d, 0x41, 0x42, 0x8a, 0xd0, 0xec, 0xbd, 0xc7, 0xbb, 0x23, 0xdf, 0x9d, 0x59, 0xe6, 0xce,
+ 0xdd, 0xc6, 0x48, 0x95, 0x20, 0x5a, 0x20, 0x2d, 0x2d, 0x6a, 0xfa, 0x52, 0x81, 0xb6, 0xbc, 0x11,
+ 0xef, 0x67, 0x81, 0x16, 0x9a, 0x52, 0xf8, 0x55, 0x9e, 0x4a, 0xcb, 0x1f, 0x9e, 0x52, 0x49, 0xff,
+ 0xb4, 0xa5, 0x94, 0xb4, 0x80, 0xc4, 0xe3, 0x0f, 0x9a, 0x7b, 0x67, 0x77, 0xef, 0xda, 0x6b, 0xf3,
+ 0xcb, 0x3b, 0xdf, 0xf7, 0xcd, 0x39, 0x67, 0xce, 0x9c, 0x39, 0x33, 0xd7, 0xe4, 0x60, 0x6b, 0xa5,
+ 0x7e, 0x0c, 0x95, 0x92, 0xca, 0x93, 0x3e, 0x86, 0xc9, 0xcf, 0x70, 0xae, 0xa5, 0xa4, 0x96, 0x14,
+ 0x6a, 0xa8, 0xf4, 0xea, 0x5c, 0x9f, 0x9e, 0x7a, 0x53, 0x9d, 0xeb, 0x46, 0x54, 0x9b, 0xf3, 0x64,
+ 0xf3, 0x58, 0x5d, 0xd6, 0xe5, 0xb1, 0x58, 0x58, 0x8b, 0x96, 0xe3, 0x51, 0x3c, 0x88, 0x7f, 0x25,
+ 0x06, 0xae, 0x7f, 0x65, 0x84, 0x6c, 0x5f, 0x40, 0xcd, 0x7c, 0xa6, 0x19, 0xbd, 0x91, 0x6c, 0x35,
+ 0x46, 0x32, 0xce, 0xac, 0x73, 0x74, 0xcf, 0xf1, 0x89, 0xb9, 0xb5, 0xc6, 0xe7, 0x72, 0xd2, 0xc7,
+ 0xc5, 0x58, 0x43, 0xdf, 0x4e, 0xf6, 0xe0, 0x39, 0x8d, 0xc2, 0x47, 0xff, 0xbd, 0x31, 0x99, 0x19,
+ 0x99, 0xdd, 0xb2, 0xc9, 0xac, 0xdd, 0x5d, 0xb5, 0x19, 0x85, 0xb4, 0x42, 0x76, 0xb5, 0x02, 0xe6,
+ 0x61, 0x43, 0x06, 0x3e, 0xaa, 0x30, 0xb3, 0x65, 0x76, 0xcb, 0xd1, 0x9d, 0xc7, 0xdf, 0xb8, 0x7e,
+ 0x72, 0x37, 0xb8, 0xb9, 0x4a, 0x4a, 0x9e, 0x17, 0x5a, 0xad, 0x2e, 0x0e, 0x58, 0xa0, 0xc7, 0xc9,
+ 0x68, 0x8b, 0x29, 0x14, 0x3a, 0xb3, 0x75, 0xd6, 0x39, 0xba, 0xf3, 0xf8, 0xd4, 0xc6, 0xb6, 0x16,
+ 0xad, 0x92, 0x66, 0xc8, 0x58, 0x13, 0xc3, 0x90, 0xd5, 0x31, 0xb3, 0x6d, 0xd6, 0x39, 0xba, 0x63,
+ 0xb1, 0x3b, 0xa4, 0x13, 0x64, 0xd4, 0x63, 0x41, 0x80, 0x2a, 0x33, 0x1a, 0x13, 0x76, 0x34, 0x75,
+ 0x92, 0xec, 0x5d, 0x17, 0x08, 0x05, 0xb2, 0x65, 0x05, 0x57, 0xe3, 0xb4, 0xed, 0x58, 0x34, 0x3f,
+ 0xe9, 0x7e, 0xb2, 0xad, 0xcd, 0x82, 0x08, 0x33, 0x23, 0x31, 0x96, 0x0c, 0xde, 0x36, 0xf2, 0x56,
+ 0xe7, 0xc6, 0xf3, 0x87, 0xc9, 0x56, 0x93, 0x02, 0x0a, 0x64, 0x57, 0x5e, 0xa9, 0x25, 0xe1, 0xe3,
+ 0x32, 0x17, 0xe8, 0xc3, 0x35, 0x74, 0x94, 0x8c, 0x9c, 0x3e, 0x05, 0x0e, 0xdd, 0x49, 0xc6, 0xf2,
+ 0x4a, 0x65, 0x59, 0x88, 0x30, 0x42, 0xf7, 0x13, 0x88, 0x65, 0xbc, 0xd9, 0x0a, 0xb0, 0x89, 0x42,
+ 0xa3, 0x0f, 0x5b, 0xe8, 0x21, 0x92, 0xc9, 0x2b, 0xb5, 0xc8, 0x84, 0x2f, 0x9b, 0x45, 0x14, 0xa8,
+ 0x98, 0x96, 0xaa, 0xc0, 0x78, 0x80, 0x3e, 0x6c, 0xa5, 0x53, 0x64, 0xc2, 0xcc, 0x59, 0x2a, 0xb9,
+ 0x6b, 0xb9, 0x6d, 0xd6, 0x5e, 0x15, 0x15, 0x67, 0x01, 0x7f, 0x3f, 0xd3, 0x5c, 0x0a, 0x18, 0xa5,
+ 0x13, 0x84, 0xe6, 0x95, 0x72, 0x31, 0x1c, 0xc0, 0xc7, 0xe8, 0x2e, 0xb2, 0x3d, 0xaf, 0x54, 0x85,
+ 0x09, 0xee, 0xc1, 0x76, 0x0a, 0x64, 0x67, 0x5e, 0xa9, 0xbc, 0x68, 0x63, 0x20, 0x5b, 0x08, 0x2f,
+ 0x8c, 0xd1, 0x6b, 0xc9, 0xfe, 0x14, 0xb2, 0x24, 0xb4, 0x8a, 0x42, 0x13, 0xe1, 0x8b, 0x63, 0xf4,
+ 0x70, 0x1c, 0x62, 0x97, 0x2a, 0x4b, 0x17, 0xdb, 0xdc, 0xc3, 0x82, 0x8c, 0x84, 0x0f, 0x2f, 0x8d,
+ 0xd1, 0x3d, 0x64, 0x47, 0x4c, 0x6b, 0xae, 0x57, 0xe1, 0xf2, 0x38, 0xdd, 0x47, 0xf6, 0xf4, 0xc6,
+ 0x25, 0xd1, 0x8a, 0x34, 0x3c, 0x33, 0x4e, 0x29, 0xd9, 0xdd, 0x03, 0x5d, 0xa6, 0x19, 0x3c, 0x3b,
+ 0x4e, 0xf7, 0x93, 0xf1, 0x1e, 0x96, 0x3f, 0xc7, 0x43, 0x1d, 0xc2, 0x6f, 0xc6, 0xe9, 0x4e, 0x32,
+ 0x9a, 0x57, 0xaa, 0x8c, 0x1a, 0x1e, 0x9b, 0xa4, 0xd7, 0x91, 0x43, 0xc9, 0x60, 0x5e, 0x48, 0xdd,
+ 0x40, 0x95, 0x0b, 0x38, 0x0a, 0x9d, 0x93, 0x42, 0xa0, 0x67, 0xa2, 0x7b, 0x7c, 0x92, 0xee, 0x8d,
+ 0xb3, 0x5f, 0x46, 0x5d, 0xd5, 0x0a, 0x59, 0x13, 0x7e, 0x38, 0x69, 0x57, 0x57, 0x46, 0x7d, 0x4b,
+ 0x84, 0x11, 0xc2, 0x8f, 0x26, 0xe9, 0x38, 0x21, 0x09, 0xe2, 0x72, 0x16, 0xc0, 0x13, 0x29, 0xa0,
+ 0xc2, 0x45, 0x1d, 0x2e, 0x4d, 0xda, 0x55, 0x18, 0xe0, 0x78, 0x05, 0x1e, 0xca, 0xd0, 0x09, 0xb2,
+ 0xb7, 0x37, 0x2e, 0xf9, 0x98, 0xac, 0xee, 0xe1, 0x0c, 0x9d, 0x8c, 0xf3, 0x9b, 0xe0, 0x95, 0xa8,
+ 0x16, 0x70, 0xef, 0x14, 0xae, 0xc2, 0x23, 0x19, 0xba, 0x3b, 0x4e, 0x70, 0xbe, 0x8d, 0x42, 0xc3,
+ 0xa7, 0x67, 0xba, 0x59, 0x30, 0xc3, 0xaa, 0x39, 0x2d, 0x0a, 0x3e, 0x33, 0x63, 0x63, 0x8d, 0xc1,
+ 0x38, 0x09, 0x9f, 0x9d, 0xb1, 0x89, 0x79, 0x17, 0x0b, 0xb8, 0x9f, 0x6c, 0xd5, 0x85, 0x23, 0xd6,
+ 0x47, 0x1f, 0x4b, 0xb2, 0x78, 0xfb, 0x11, 0x9a, 0x21, 0xfb, 0x06, 0x88, 0x85, 0xd5, 0x10, 0x83,
+ 0x65, 0xb8, 0xe3, 0x88, 0x35, 0x53, 0x61, 0x75, 0x2e, 0x12, 0x33, 0x57, 0xe7, 0x28, 0x21, 0xdb,
+ 0x4c, 0x29, 0xd4, 0xe0, 0xb7, 0x27, 0x6c, 0x4a, 0xdc, 0x5a, 0x4e, 0x21, 0xd3, 0x08, 0xbf, 0xeb,
+ 0x23, 0x4b, 0x2d, 0xdf, 0x20, 0xbf, 0xef, 0x23, 0x2e, 0x06, 0xa8, 0x11, 0xfe, 0x70, 0xc2, 0x26,
+ 0xc1, 0xad, 0x95, 0xa5, 0x6e, 0x70, 0x51, 0x4f, 0xb6, 0xfc, 0x8f, 0x27, 0x6c, 0x80, 0x6e, 0xad,
+ 0x24, 0x34, 0x2a, 0xc1, 0x82, 0xbc, 0x39, 0x99, 0xf0, 0xa7, 0x13, 0x36, 0x8b, 0x39, 0xb5, 0xda,
+ 0xd2, 0x12, 0x9e, 0x7a, 0x87, 0x5d, 0x70, 0x32, 0xae, 0xf2, 0x3a, 0x7c, 0xfe, 0xa4, 0x2d, 0xb4,
+ 0x1e, 0xb4, 0xc0, 0xc3, 0x26, 0xd3, 0x5e, 0x03, 0xbe, 0x70, 0xd2, 0x9a, 0xed, 0x51, 0x05, 0xa9,
+ 0x9a, 0x4c, 0xc3, 0x17, 0x4f, 0xd2, 0x03, 0x71, 0xa9, 0x27, 0x44, 0x5e, 0x78, 0xe6, 0x2f, 0x5c,
+ 0xb8, 0x69, 0x00, 0x76, 0x31, 0x81, 0x5f, 0xbe, 0x69, 0xc0, 0xa9, 0xd9, 0x9c, 0xcb, 0xf3, 0xb6,
+ 0xd4, 0x7a, 0x50, 0x11, 0x05, 0x3c, 0x33, 0x3f, 0xe0, 0xef, 0x14, 0xae, 0xba, 0x68, 0x9a, 0x0b,
+ 0x3c, 0x3b, 0x6f, 0xd7, 0xdd, 0x0b, 0xc4, 0x6b, 0x30, 0x2e, 0xe0, 0xd1, 0xac, 0xcd, 0xf2, 0xbc,
+ 0xe7, 0x2d, 0x30, 0xc1, 0xea, 0xa8, 0xe0, 0x4b, 0x05, 0x3a, 0x45, 0x0e, 0x0c, 0x60, 0x25, 0xc1,
+ 0x75, 0xd9, 0xd8, 0xf9, 0x72, 0xc1, 0xba, 0xed, 0x73, 0x6e, 0x0d, 0xbe, 0x52, 0xb0, 0xbb, 0x98,
+ 0x46, 0xcd, 0x1c, 0xf8, 0xea, 0x30, 0xc6, 0x55, 0xb2, 0x05, 0x5f, 0x2b, 0xd8, 0x50, 0xd3, 0xcc,
+ 0x02, 0xaf, 0xc3, 0xd7, 0x87, 0x11, 0x2e, 0x57, 0xf0, 0x8d, 0x02, 0x3d, 0x18, 0xb7, 0x8e, 0x3e,
+ 0x51, 0x96, 0xfa, 0x74, 0x0b, 0x4d, 0x7f, 0xfa, 0x66, 0xc1, 0x66, 0xae, 0x4f, 0xe6, 0x96, 0xeb,
+ 0x70, 0x67, 0xd1, 0xee, 0xcd, 0x00, 0x5c, 0x66, 0x4d, 0x84, 0xbb, 0x8a, 0x74, 0x86, 0x4c, 0xad,
+ 0xa5, 0x2a, 0x2c, 0x0c, 0x5b, 0x0d, 0x65, 0xba, 0xdb, 0xc7, 0x8a, 0xeb, 0x62, 0x37, 0x73, 0x51,
+ 0xc3, 0xdd, 0x45, 0x7a, 0x88, 0x4c, 0xae, 0x65, 0x8a, 0xaa, 0xe5, 0x55, 0x55, 0x1b, 0x2e, 0x16,
+ 0xd7, 0x85, 0x92, 0x95, 0x1a, 0xae, 0xae, 0x0f, 0x25, 0x2b, 0x75, 0x9c, 0xa5, 0x57, 0x8b, 0xeb,
+ 0x56, 0x96, 0x95, 0x3a, 0x7f, 0x8e, 0x9b, 0x76, 0xf0, 0x5a, 0xd1, 0x6e, 0x51, 0x4e, 0x0a, 0xcd,
+ 0x3c, 0xbd, 0x88, 0xef, 0x83, 0xbb, 0xcb, 0xdd, 0x3a, 0xe9, 0x61, 0xa6, 0x28, 0x2e, 0x96, 0x6d,
+ 0x5c, 0x03, 0xf0, 0x02, 0x0f, 0x43, 0xd3, 0x10, 0xee, 0x29, 0xdb, 0x7d, 0xed, 0xb3, 0x71, 0x87,
+ 0x32, 0xdc, 0xbd, 0x65, 0xbb, 0xd6, 0x3e, 0x67, 0xcf, 0xe1, 0x7d, 0x6b, 0x5c, 0xdd, 0x8c, 0xa2,
+ 0xae, 0x1b, 0x70, 0x7f, 0xb9, 0x5b, 0x92, 0x09, 0x5c, 0x72, 0xe1, 0x81, 0xb2, 0xed, 0x73, 0x26,
+ 0xf1, 0xff, 0x5a, 0xea, 0x46, 0xbd, 0x5c, 0xef, 0x06, 0xf0, 0xef, 0xa5, 0xee, 0x9c, 0xe5, 0xba,
+ 0xb5, 0xfe, 0x9f, 0x94, 0x2c, 0x69, 0xc1, 0x21, 0xfc, 0x77, 0xc9, 0x36, 0x9a, 0xa4, 0xc7, 0xcc,
+ 0x07, 0x9c, 0x85, 0xf0, 0xdc, 0x59, 0x5b, 0xc0, 0x29, 0xd0, 0x54, 0xfc, 0x9f, 0xcf, 0xda, 0x5d,
+ 0x4c, 0xe1, 0x65, 0x99, 0x63, 0xc2, 0x37, 0xed, 0x04, 0x43, 0xb8, 0x32, 0x44, 0x90, 0xb4, 0x07,
+ 0x7b, 0xe9, 0x3c, 0x7f, 0xb6, 0x7b, 0x92, 0xa4, 0x68, 0xa3, 0x0a, 0x93, 0x56, 0xf3, 0x34, 0x76,
+ 0x0f, 0x4c, 0x0a, 0x2d, 0xb9, 0xf0, 0x33, 0xec, 0x1e, 0xf6, 0x14, 0x7e, 0x86, 0xeb, 0x00, 0xe1,
+ 0xe7, 0x43, 0x29, 0xd9, 0xe2, 0x1e, 0xfc, 0x62, 0x18, 0x55, 0x12, 0xcb, 0x32, 0x84, 0x5f, 0x62,
+ 0x3f, 0xf3, 0x3d, 0xea, 0x14, 0x17, 0x3e, 0xfc, 0x0a, 0x6d, 0x55, 0xa4, 0x99, 0x05, 0x6c, 0xd6,
+ 0x50, 0x85, 0xf0, 0x6b, 0xa4, 0xaf, 0x23, 0x33, 0x43, 0xc9, 0x52, 0x78, 0x5a, 0xe0, 0x19, 0x79,
+ 0x5a, 0x20, 0x5c, 0xac, 0x0f, 0x31, 0x51, 0x0a, 0x8b, 0x4a, 0x46, 0x2d, 0xb8, 0xa7, 0xde, 0xaf,
+ 0x87, 0x14, 0x59, 0x88, 0x82, 0x00, 0xee, 0xad, 0xf7, 0x2b, 0x29, 0xc5, 0x25, 0x0e, 0xe0, 0xbe,
+ 0xba, 0xbd, 0x3f, 0xd3, 0x6c, 0x11, 0xb5, 0xa5, 0xef, 0xdf, 0x80, 0x3e, 0x7d, 0xab, 0x30, 0xa1,
+ 0x3f, 0x30, 0xcc, 0xaf, 0x9d, 0xfa, 0x04, 0x1f, 0xe2, 0xd7, 0x2e, 0xcb, 0x85, 0x4b, 0x9c, 0xce,
+ 0x92, 0x83, 0x43, 0xd9, 0xaa, 0x66, 0x3a, 0x0a, 0xe1, 0x49, 0x6e, 0xaf, 0xd7, 0xf5, 0x0a, 0x5b,
+ 0xa8, 0xf0, 0x63, 0x4e, 0x6f, 0x20, 0xd3, 0x9b, 0x49, 0x4a, 0x2e, 0x3c, 0xc5, 0xe9, 0x1b, 0xc8,
+ 0x75, 0x1b, 0x89, 0xfa, 0x65, 0xf2, 0x13, 0x4e, 0x8f, 0x92, 0x1b, 0xfe, 0xaf, 0xae, 0xe4, 0xc2,
+ 0x4f, 0x37, 0x8e, 0xbd, 0x24, 0xda, 0x5c, 0x23, 0x7c, 0x68, 0xc5, 0x56, 0xea, 0x7a, 0xc5, 0xcd,
+ 0xc8, 0xda, 0x08, 0x1f, 0x5e, 0xa1, 0xd7, 0x93, 0xc3, 0xc3, 0x97, 0x8f, 0x3a, 0x29, 0xc2, 0x8f,
+ 0x6c, 0xae, 0x89, 0xab, 0xf1, 0xc2, 0xa6, 0x9a, 0x78, 0x97, 0xe0, 0xf6, 0x8d, 0x83, 0xc9, 0x06,
+ 0xd2, 0x5b, 0x81, 0x3b, 0x56, 0x36, 0xcc, 0xf4, 0x92, 0xa8, 0xc5, 0x92, 0x8f, 0xae, 0xd0, 0x69,
+ 0x72, 0xed, 0x50, 0xc9, 0x22, 0x32, 0x1f, 0xee, 0xdc, 0xd8, 0xc7, 0xbb, 0x95, 0xc9, 0xc8, 0x5d,
+ 0x2b, 0x74, 0x57, 0xfc, 0xda, 0xac, 0x44, 0x61, 0x03, 0xbe, 0xd5, 0xb4, 0xc5, 0x6c, 0x46, 0x4b,
+ 0x62, 0x45, 0xc8, 0x5b, 0x45, 0x45, 0xc9, 0x36, 0x37, 0x0f, 0x91, 0x6f, 0x37, 0xed, 0x29, 0x36,
+ 0x64, 0x0f, 0xfd, 0x4e, 0xd3, 0x56, 0xa2, 0x41, 0x4b, 0xa2, 0x6d, 0x1e, 0x19, 0xc9, 0xc3, 0x67,
+ 0x99, 0xa3, 0x82, 0xef, 0x36, 0x6d, 0x00, 0x29, 0xba, 0x8a, 0xaa, 0x1d, 0x6f, 0xde, 0x32, 0xaf,
+ 0xc3, 0xa3, 0x69, 0x97, 0xb6, 0x8d, 0x65, 0x23, 0xe1, 0x07, 0x58, 0xf2, 0xe1, 0x7b, 0x4d, 0xbb,
+ 0xbc, 0x54, 0x3c, 0x2e, 0x9a, 0x7e, 0x9a, 0xd4, 0xc6, 0xf7, 0xd3, 0xd6, 0xb3, 0x4a, 0x32, 0xdf,
+ 0x63, 0xa1, 0x4e, 0xb9, 0xff, 0x41, 0xd3, 0xde, 0x74, 0x29, 0xf7, 0x67, 0x56, 0x5b, 0x08, 0x8f,
+ 0x35, 0x6d, 0xcf, 0x1d, 0x98, 0x09, 0x8f, 0x77, 0xd7, 0x58, 0x96, 0xc6, 0x82, 0x97, 0xb8, 0x79,
+ 0x30, 0xb2, 0x61, 0xa4, 0xd1, 0x05, 0xa6, 0xc2, 0x06, 0x0b, 0x0a, 0xb9, 0x05, 0xf8, 0x78, 0x64,
+ 0xc3, 0x18, 0xc2, 0xcf, 0x57, 0xca, 0x55, 0xf8, 0xc4, 0x26, 0x82, 0x85, 0x5b, 0xce, 0x9c, 0x81,
+ 0x4f, 0x46, 0xb6, 0x74, 0xd3, 0x82, 0x25, 0xd1, 0xec, 0xfb, 0x78, 0x28, 0xea, 0xbe, 0x6a, 0x87,
+ 0x29, 0x62, 0x2f, 0x0f, 0x6f, 0x2a, 0x89, 0xfd, 0x3c, 0x12, 0xd9, 0x6c, 0xa7, 0x25, 0x8b, 0xe8,
+ 0x21, 0x6f, 0x23, 0x7c, 0x2a, 0xb2, 0xb5, 0x10, 0xbf, 0x43, 0x3e, 0x70, 0x9b, 0xed, 0x9a, 0x66,
+ 0x64, 0xb2, 0x14, 0x4f, 0xa9, 0x46, 0x35, 0xf8, 0xe0, 0x6d, 0xf4, 0xf5, 0x71, 0x63, 0x34, 0xcc,
+ 0x3b, 0x99, 0xd9, 0xab, 0x74, 0x79, 0xd9, 0x97, 0xe1, 0xa5, 0xf3, 0xce, 0xa6, 0x32, 0x7b, 0x24,
+ 0x9f, 0x3c, 0xef, 0xd0, 0x3d, 0xf1, 0x1b, 0x38, 0xd7, 0x88, 0xc4, 0x0a, 0xbc, 0xd0, 0x71, 0xe8,
+ 0x44, 0x72, 0x1b, 0x9a, 0x71, 0x96, 0xf9, 0x25, 0xe1, 0xe3, 0x39, 0x78, 0xb1, 0xe3, 0xd0, 0x03,
+ 0xc9, 0x25, 0x62, 0xf1, 0xf8, 0x29, 0xfc, 0x52, 0xc7, 0xa1, 0x99, 0xe4, 0x3d, 0x66, 0xe1, 0x6a,
+ 0xc0, 0x3d, 0x2c, 0xb9, 0xf0, 0x97, 0x8e, 0x43, 0x0f, 0x25, 0x9d, 0x39, 0xcd, 0xd8, 0xcb, 0xf5,
+ 0xe5, 0x8e, 0x43, 0xa7, 0x93, 0x0e, 0x6a, 0xd8, 0x98, 0x2a, 0x4b, 0x9d, 0x93, 0xe6, 0x2b, 0x4b,
+ 0x23, 0xfc, 0x75, 0x5d, 0x18, 0xb1, 0x04, 0x5e, 0xe9, 0x38, 0x74, 0x26, 0x39, 0x71, 0x06, 0x77,
+ 0x19, 0x36, 0xa5, 0xa8, 0x6a, 0xa9, 0x58, 0x1d, 0x2b, 0x4c, 0x37, 0xe0, 0x6f, 0x1d, 0x87, 0xce,
+ 0x26, 0x47, 0xae, 0x2f, 0x30, 0x2f, 0x28, 0x13, 0x6e, 0xcd, 0x3c, 0x7a, 0xae, 0x76, 0x1c, 0xba,
+ 0x2f, 0xb9, 0x91, 0x7b, 0xae, 0xe1, 0xd5, 0xc1, 0xe5, 0xc5, 0x9f, 0x08, 0x61, 0x03, 0x5e, 0xeb,
+ 0x38, 0x94, 0x26, 0x17, 0x7a, 0xac, 0x35, 0x3d, 0xea, 0xef, 0x1d, 0x87, 0x1e, 0x4c, 0xba, 0xbb,
+ 0xc1, 0x0a, 0x5c, 0x24, 0xb1, 0x65, 0x57, 0x4b, 0x2e, 0xfc, 0x63, 0x3d, 0x39, 0x1f, 0x04, 0x31,
+ 0x1f, 0xc2, 0x3f, 0x3b, 0xce, 0xd4, 0xd6, 0x0b, 0x9f, 0x9b, 0xbe, 0x26, 0xfb, 0xe6, 0xa7, 0xaf,
+ 0x4c, 0x3b, 0x97, 0xaf, 0x4c, 0x3b, 0xcf, 0x5d, 0x99, 0x76, 0x1e, 0x7c, 0x7e, 0xfa, 0x9a, 0xf7,
+ 0x4c, 0x27, 0x1f, 0xcb, 0x1a, 0xbd, 0xc6, 0x31, 0x4f, 0x2a, 0x3c, 0x36, 0xf8, 0x5f, 0x87, 0xda,
+ 0x68, 0xfc, 0xef, 0x82, 0xb7, 0xfc, 0x2f, 0x00, 0x00, 0xff, 0xff, 0xba, 0x95, 0xf6, 0x6d, 0x8e,
0x10, 0x00, 0x00,
}
diff --git a/core/pkg/errorcodes/errors.proto b/core/pkg/errorcodes/errors.proto
index 67110bbf5a..421079be96 100644
--- a/core/pkg/errorcodes/errors.proto
+++ b/core/pkg/errorcodes/errors.proto
@@ -120,7 +120,6 @@ enum Code {
ErrConversationIsMember = 13204;
ErrConversationGetMember = 13205;
ErrConversationGetOwners = 13206;
- ErrConversationGetInteractiveMember = 13207;
ErrConversationMember = 13500;
ErrConversationMemberID = 13501;
diff --git a/core/sql/helpers.go b/core/sql/helpers.go
index 4d8002a59b..686752ee85 100644
--- a/core/sql/helpers.go
+++ b/core/sql/helpers.go
@@ -158,19 +158,25 @@ func ConversationSave(db *gorm.DB, c *entity.Conversation) error {
var err error
for _, member := range c.Members {
- err := db.Find(&entity.Contact{ID: member.Contact.ID}).Error
- if err != nil {
- if !errorcodes.ErrDbNothingFound.Is(GenericError(err)) {
- return err
- }
- if err := db.Save(member.Contact).Error; err != nil {
- return err
+ if member.Contact != nil {
+ err := db.Find(&entity.Contact{ID: member.Contact.ID}).Error
+ if err != nil {
+ if !errorcodes.ErrDbNothingFound.Is(GenericError(err)) {
+ db.Delete(c)
+ return err
+ }
+ member.Contact.Status = entity.Contact_Unknown
+ if err := db.Save(member.Contact).Error; err != nil {
+ db.Delete(c)
+ return err
+ }
}
}
if err = db.Save(member).Error; err != nil {
+ db.Delete(c)
return err
}
}
- return err
+ return nil
}
diff --git a/core/sql/migrations/v0006conversationLogic/migration.go b/core/sql/migrations/v0006conversationLogic/migration.go
index 4f2a754f61..08440b7604 100644
--- a/core/sql/migrations/v0006conversationLogic/migration.go
+++ b/core/sql/migrations/v0006conversationLogic/migration.go
@@ -44,7 +44,7 @@ func GetMigration() *gormigrate.Migration {
return nil
},
Rollback: func(tx *gorm.DB) error {
- if err := tx.Table("conversation").DropColumn("kind").Error; err != nil {
+ if err := tx.Table("conversation").DropColumn("kind").DropColumn("wrote_at").Error; err != nil {
return err
}
return nil
@@ -120,11 +120,12 @@ type Conversation struct {
CreatedAt time.Time `protobuf:"bytes,2,opt,name=created_at,json=createdAt,proto3,stdtime" json:"created_at"`
UpdatedAt time.Time `protobuf:"bytes,3,opt,name=updated_at,json=updatedAt,proto3,stdtime" json:"updated_at"`
ReadAt time.Time `protobuf:"bytes,4,opt,name=read_at,json=readAt,proto3,stdtime" json:"read_at"`
+ WroteAt time.Time `protobuf:"bytes,5,opt,name=wrote_at,json=wroteAt,proto3,stdtime" json:"wrote_at"`
Title string `protobuf:"bytes,20,opt,name=title,proto3" json:"title,omitempty"`
Topic string `protobuf:"bytes,21,opt,name=topic,proto3" json:"topic,omitempty"`
Infos string `protobuf:"bytes,22,opt,name=infos,proto3" json:"infos,omitempty"`
Kind Conversation_Kind `protobuf:"varint,23,opt,name=kind,proto3,enum=berty.entity.Conversation_Kind" json:"kind,omitempty"`
- Members []*ConversationMember `protobuf:"bytes,100,rep,name=members,proto3" json:"members,omitempty" gorm:"foreignkey:ConversationID;association_foreignkey:ID"`
+ Members []*ConversationMember `protobuf:"bytes,100,rep,name=members,proto3" json:"members,omitempty" gorm:"foreignkey:ConversationID;association_foreignkey:ID;save_associations:true"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@@ -135,11 +136,11 @@ type ConversationMember struct {
CreatedAt time.Time `protobuf:"bytes,2,opt,name=created_at,json=createdAt,proto3,stdtime" json:"created_at"`
UpdatedAt time.Time `protobuf:"bytes,3,opt,name=updated_at,json=updatedAt,proto3,stdtime" json:"updated_at"`
ReadAt time.Time `protobuf:"bytes,4,opt,name=read_at,json=readAt,proto3,stdtime" json:"read_at"`
+ WroteAt time.Time `protobuf:"bytes,5,opt,name=wrote_at,json=wroteAt,proto3,stdtime" json:"wrote_at"`
Status ConversationMember_Status `protobuf:"varint,10,opt,name=status,proto3,enum=berty.entity.ConversationMember_Status" json:"status,omitempty"`
- Contact *Contact `protobuf:"bytes,100,opt,name=contact,proto3" json:"contact,omitempty"`
+ Contact *Contact `protobuf:"bytes,100,opt,name=contact,proto3" json:"contact,omitempty" gorm:"association_autoupdate:false;association_create:true"`
ConversationID string `protobuf:"bytes,101,opt,name=conversation_id,json=conversationId,proto3" json:"conversation_id,omitempty"`
ContactID string `protobuf:"bytes,102,opt,name=contact_id,json=contactId,proto3" json:"contact_id,omitempty"`
- Conversation *Conversation `protobuf:"bytes,103,opt,name=conversation,proto3" json:"conversation,omitempty" gorm:"PRELOAD:false;foreignkey:ID;association_foreignkey:ConversationID"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`