From 78756c5a2dc0dca3f6b55be17ca70d842b5b906d Mon Sep 17 00:00:00 2001 From: Godefroy Ponsinet Date: Wed, 28 Nov 2018 17:58:40 +0100 Subject: [PATCH] feat: conversation mark as read Signed-off-by: Godefroy Ponsinet --- .../Library/PublicKeyWithActions.js | 113 ++++-- .../common/components/Screens/Chats/Detail.js | 9 +- .../common/components/Screens/Chats/List.js | 39 +- .../common/graphql/fragments/Conversation.js | 1 + .../graphql/mutations/ConversationRead.js | 52 +++ .../common/graphql/mutations/EventSeen.js | 17 +- .../common/graphql/mutations/index.js | 1 + .../graphql/queries/ConversationList.js | 2 +- client/react-native/common/schema.graphql | 9 +- .../jsonclient/berty.node.service.gen.go | 16 +- core/api/node/graphql/gqlgen.gen.yml | 19 + .../graphql/graph/generated/generated.gen.go | 267 +++++++++++-- core/api/node/graphql/resolver.go | 30 +- core/api/node/graphql/service.gen.graphql | 9 +- core/api/node/service.proto | 7 + core/api/protobuf/graphql/graphql.go | 5 + core/api/protobuf/graphql/graphql.pb.go | 357 ++++++++++++++++-- core/api/protobuf/graphql/graphql.proto | 5 + core/entity/conversation.pb.go | 135 ++++--- core/entity/conversation.proto | 1 + core/go.mod | 16 +- core/go.sum | 14 + core/node/event_handlers.go | 3 +- core/node/nodeapi.go | 46 ++- 24 files changed, 996 insertions(+), 177 deletions(-) create mode 100644 client/react-native/common/graphql/mutations/ConversationRead.js create mode 100644 core/api/protobuf/graphql/graphql.go diff --git a/client/react-native/common/components/Library/PublicKeyWithActions.js b/client/react-native/common/components/Library/PublicKeyWithActions.js index df031f3d75..7bbaa8bed1 100644 --- a/client/react-native/common/components/Library/PublicKeyWithActions.js +++ b/client/react-native/common/components/Library/PublicKeyWithActions.js @@ -1,4 +1,11 @@ -import { ScrollView, TextInput, Platform, Clipboard, TouchableNativeFeedback, TouchableOpacity } from 'react-native' +import { + ScrollView, + TextInput, + Platform, + Clipboard, + TouchableNativeFeedback, + TouchableOpacity, +} from 'react-native' import { btoa } from 'b64-lite' import React, { PureComponent } from 'react' @@ -6,7 +13,8 @@ import { Button, Flex, TextInputMultilineFix, Text } from './index' import { RelayContext } from '../../relay' import { colors } from '../../constants' import { - extractPublicKeyFromId, makeShareableUrl, + extractPublicKeyFromId, + makeShareableUrl, shareLinkOther, shareLinkSelf, } from '../../helpers/contacts' @@ -133,10 +141,23 @@ export default class PublicKeyWithActions extends PureComponent { } const modeButtons = [ - { element: () => }, { - element: () => , + element: () => ( + + ), + }, + { + element: () => ( + + ), }, ] @@ -144,11 +165,13 @@ export default class PublicKeyWithActions extends PureComponent { - {mode === 'key' || (readOnly) - ? - this.setState({ contact: { ...this.state.contact, displayName } }) + this.setState({ + contact: { ...this.state.contact, displayName }, + }) } value={displayName} style={[ @@ -163,22 +186,29 @@ export default class PublicKeyWithActions extends PureComponent { rounded, ]} /> - : {' '} - } + ) : ( + + )} {/* TODO: Use a lighter button group impl? */} this.setState({ mode: mode === 'key' ? 'qrcode' : 'key' })} + onPress={() => + this.setState({ mode: mode === 'key' ? 'qrcode' : 'key' }) + } selectedIndex={mode === 'key' ? 0 : 1} buttons={modeButtons} containerStyle={{ height: 32, flex: 1 }} selectedBackgroundColor={colors.green} - component={Platform.OS === 'android' ? TouchableNativeFeedback : TouchableOpacity} + component={ + Platform.OS === 'android' + ? TouchableNativeFeedback + : TouchableOpacity + } /> - {mode === 'key' - ? - : null} + ) : null} - {!readOnly && mode === 'qrcode' - ? { - const url = parseUrl(data) + {!readOnly && mode === 'qrcode' ? ( + { + const url = parseUrl(data) - if (!url || url.pathname !== '/add-contact' || url.hashParts['public-key'] === '') { - return - } + if ( + !url || + url.pathname !== '/add-contact' || + url.hashParts['public-key'] === '' + ) { + return + } - this.setState({ - mode: 'key', - contact: { - ...this.state.contact, - id: url.hashParts['public-key'], - displayName: url.hashParts['display-name'] || '', - }, - }) - }} /> : null} - {readOnly && mode === 'qrcode' - ? + ) : null} + {readOnly && mode === 'qrcode' ? ( + - : null // TODO: implement camera + style={[marginTop]} + /> + ) : null // TODO: implement camera } {shareButton ? ( @@ -241,7 +280,11 @@ export default class PublicKeyWithActions extends PureComponent { onPress={this.onSubmit} /> ) : null} - {errors.map((err, i) => {err.extensions.message})} + {errors.map((err, i) => ( + + {err.extensions.message} + + ))} ) diff --git a/client/react-native/common/components/Screens/Chats/Detail.js b/client/react-native/common/components/Screens/Chats/Detail.js index 6d69592864..ca7becafb6 100644 --- a/client/react-native/common/components/Screens/Chats/Detail.js +++ b/client/react-native/common/components/Screens/Chats/Detail.js @@ -25,7 +25,7 @@ class Message extends React.PureComponent { } await this.props.screenProps.context.mutations.eventSeen({ - eventId: this.props.data.id, + id: this.props.data.id, }) } @@ -102,6 +102,13 @@ class Input extends PureComponent { height: 16, } + async componentDidMount () { + const conversation = this.props.navigation.getParam('conversation') + await this.props.screenProps.context.mutations.conversationRead({ + id: conversation.id, + }) + } + onSubmit = () => { const { input } = this.state this.setState({ input: '' }, async () => { diff --git a/client/react-native/common/components/Screens/Chats/List.js b/client/react-native/common/components/Screens/Chats/List.js index c9032c9b49..474749671e 100644 --- a/client/react-native/common/components/Screens/Chats/List.js +++ b/client/react-native/common/components/Screens/Chats/List.js @@ -1,19 +1,44 @@ +import { Image } from 'react-native' import React, { PureComponent } from 'react' +import { Flex, Header, Screen, Text } from '../../Library' import { Pagination } from '../../../relay' -import { Screen, Header, ListItem } from '../../Library' +import { borderBottom, marginLeft, padding } from '../../../styles' import { colors } from '../../../constants' import { fragments } from '../../../graphql' import { conversation as utils } from '../../../utils' -const Item = fragments.Conversation(({ data, navigation, onPress }) => { +const Item = fragments.Conversation(({ data, navigation }) => { + const { id, updatedAt, readAt } = data + const isInvite = new Date(updatedAt).getTime() > 0 + const isRead = new Date(readAt).getTime() > 0 return ( - navigation.push('chats/detail', { conversation: data })} - /> + style={[{ height: 72 }, padding, borderBottom]} + > + + + + + + {utils.getTitle(data)} + + + {isRead + ? 'No new message' + : isInvite + ? 'You have been invited' + : 'You have a new message'} + + + ) }) diff --git a/client/react-native/common/graphql/fragments/Conversation.js b/client/react-native/common/graphql/fragments/Conversation.js index a063ed6cf9..fc84c2c499 100644 --- a/client/react-native/common/graphql/fragments/Conversation.js +++ b/client/react-native/common/graphql/fragments/Conversation.js @@ -8,6 +8,7 @@ export default component => id createdAt updatedAt + readAt title topic members { diff --git a/client/react-native/common/graphql/mutations/ConversationRead.js b/client/react-native/common/graphql/mutations/ConversationRead.js new file mode 100644 index 0000000000..7cf29aef9a --- /dev/null +++ b/client/react-native/common/graphql/mutations/ConversationRead.js @@ -0,0 +1,52 @@ +import { graphql } from 'react-relay' +import { commit } from '../../relay' + +const ConversationReadMutation = graphql` + mutation ConversationReadMutation($id: ID!) { + ConversationRead(id: $id) { + id + createdAt + updatedAt + readAt + title + topic + members { + id + createdAt + updatedAt + status + contact { + id + createdAt + updatedAt + sigchain + status + devices { + id + createdAt + updatedAt + name + status + apiVersion + contactId + } + displayName + displayStatus + overrideDisplayName + overrideDisplayStatus + } + conversationId + contactId + } + } + } +` + +export default context => (input, configs) => + commit( + context.environment, + ConversationReadMutation, + 'ConversationRead', + input, + configs + ) diff --git a/client/react-native/common/graphql/mutations/EventSeen.js b/client/react-native/common/graphql/mutations/EventSeen.js index 795698d251..f2708b2105 100644 --- a/client/react-native/common/graphql/mutations/EventSeen.js +++ b/client/react-native/common/graphql/mutations/EventSeen.js @@ -1,11 +1,9 @@ import { graphql } from 'react-relay' import { commit } from '../../relay' -import { merge } from '../../helpers' -import { conversation } from '../../utils' const EventSeenMutation = graphql` - mutation EventSeenMutation($eventId: ID!) { - EventSeen(eventId: $eventId) { + mutation EventSeenMutation($id: ID!) { + EventSeen(id: $id) { id senderId createdAt @@ -26,13 +24,4 @@ const EventSeenMutation = graphql` ` export default context => (input, configs) => - commit( - context.environment, - EventSeenMutation, - 'EventSeen', - merge([ - { conversation: conversation.default, message: { text: '' } }, - input, - ]), - configs - ) + commit(context.environment, EventSeenMutation, 'EventSeen', input, configs) diff --git a/client/react-native/common/graphql/mutations/index.js b/client/react-native/common/graphql/mutations/index.js index eb9b3bb516..086948e43a 100644 --- a/client/react-native/common/graphql/mutations/index.js +++ b/client/react-native/common/graphql/mutations/index.js @@ -6,6 +6,7 @@ export contactRemove from './ContactRemove' export conversationCreate from './ConversationCreate' export conversationAddMessage from './ConversationAddMessage' export conversationInvite from './ConversationInvite' +export conversationRead from './ConversationRead' export eventSeen from './EventSeen' export debugRequeueEvent from './DebugRequeueEvent' export debugRequeueAll from './DebugRequeueAll' diff --git a/client/react-native/common/graphql/queries/ConversationList.js b/client/react-native/common/graphql/queries/ConversationList.js index 90c246add9..a2b57a8d61 100644 --- a/client/react-native/common/graphql/queries/ConversationList.js +++ b/client/react-native/common/graphql/queries/ConversationList.js @@ -23,7 +23,7 @@ const query = graphql` const defaultVariables = { filter: null, - orderBy: '', + orderBy: 'updated_at', orderDesc: false, count: 50, cursor: '', diff --git a/client/react-native/common/schema.graphql b/client/react-native/common/schema.graphql index 7c6941ce7d..293d195a6c 100644 --- a/client/react-native/common/schema.graphql +++ b/client/react-native/common/schema.graphql @@ -303,6 +303,7 @@ type BertyEntityConversation implements Node { id: ID! createdAt: GoogleProtobufTimestamp updatedAt: GoogleProtobufTimestamp + readAt: GoogleProtobufTimestamp title: String! topic: String! members: [BertyEntityConversationMember] @@ -595,6 +596,7 @@ type BertyEntityConversationPayload { id: ID! createdAt: GoogleProtobufTimestamp updatedAt: GoogleProtobufTimestamp + readAt: GoogleProtobufTimestamp title: String! topic: String! members: [BertyEntityConversationMember] @@ -612,6 +614,7 @@ input BertyEntityConversationInput { id: ID! createdAt: GoogleProtobufTimestampInput updatedAt: GoogleProtobufTimestampInput + readAt: GoogleProtobufTimestampInput title: String! topic: String! members: [BertyEntityConversationMemberInput] @@ -735,6 +738,7 @@ type Query { id: ID! createdAt: GoogleProtobufTimestampInput updatedAt: GoogleProtobufTimestampInput + readAt: GoogleProtobufTimestampInput title: String! topic: String! members: [BertyEntityConversationMemberInput] @@ -772,7 +776,7 @@ type Query { type Mutation { EventSeen( - eventId: ID! + id: ID! ): BertyP2pEventPayload ContactRequest( contact: BertyEntityContactInput @@ -831,6 +835,9 @@ type Mutation { conversation: BertyEntityConversationInput message: BertyEntityMessageInput ): BertyP2pEventPayload + ConversationRead( + id: ID! + ): BertyEntityConversationPayload GenerateFakeData( T: Bool! ): BertyNodeVoidPayload diff --git a/core/api/client/jsonclient/berty.node.service.gen.go b/core/api/client/jsonclient/berty.node.service.gen.go index a6381f892e..dd35eadb05 100644 --- a/core/api/client/jsonclient/berty.node.service.gen.go +++ b/core/api/client/jsonclient/berty.node.service.gen.go @@ -8,6 +8,7 @@ import ( "berty.tech/core/api/client" "berty.tech/core/api/node" "berty.tech/core/api/p2p" + "berty.tech/core/api/protobuf/graphql" "berty.tech/core/entity" "berty.tech/core/network" "go.uber.org/zap" @@ -32,6 +33,7 @@ func init() { registerUnary("berty.node.ConversationAddMessage", NodeConversationAddMessage) registerUnary("berty.node.GetConversation", NodeGetConversation) registerUnary("berty.node.GetConversationMember", NodeGetConversationMember) + registerUnary("berty.node.ConversationRead", NodeConversationRead) registerUnary("berty.node.HandleEvent", NodeHandleEvent) registerUnary("berty.node.GenerateFakeData", NodeGenerateFakeData) registerUnary("berty.node.RunIntegrationTests", NodeRunIntegrationTests) @@ -135,7 +137,7 @@ func NodeEventSeen(client *client.Client, ctx context.Context, jsonInput []byte) zap.String("method", "EventSeen"), zap.String("input", string(jsonInput)), ) - var typedInput node.EventIDInput + var typedInput graphql.Node if err := json.Unmarshal(jsonInput, &typedInput); err != nil { return nil, err } @@ -329,6 +331,18 @@ func NodeGetConversationMember(client *client.Client, ctx context.Context, jsonI } return client.Node().GetConversationMember(ctx, &typedInput) } +func NodeConversationRead(client *client.Client, ctx context.Context, jsonInput []byte) (interface{}, error) { + logger().Debug("client call", + zap.String("service", "Service"), + zap.String("method", "ConversationRead"), + zap.String("input", string(jsonInput)), + ) + var typedInput graphql.Node + if err := json.Unmarshal(jsonInput, &typedInput); err != nil { + return nil, err + } + return client.Node().ConversationRead(ctx, &typedInput) +} func NodeHandleEvent(client *client.Client, ctx context.Context, jsonInput []byte) (interface{}, error) { logger().Debug("client call", zap.String("service", "Service"), diff --git a/core/api/node/graphql/gqlgen.gen.yml b/core/api/node/graphql/gqlgen.gen.yml index db52806317..4e123b88aa 100644 --- a/core/api/node/graphql/gqlgen.gen.yml +++ b/core/api/node/graphql/gqlgen.gen.yml @@ -832,6 +832,22 @@ models: totalNetworkBandwidth: peersCount: + GqlNode: + model: berty.tech/core/api/protobuf/graphql.Node + fields: + id: + resolver: true + GqlNodeInput: + model: berty.tech/core/api/protobuf/graphql.Node + fields: + id: + resolver: true + GqlNodePayload: + model: berty.tech/core/api/protobuf/graphql.Node + fields: + id: + resolver: true + BertyEntityDevice: @@ -920,6 +936,7 @@ models: resolver: true createdAt: updatedAt: + readAt: title: topic: members: @@ -930,6 +947,7 @@ models: resolver: true createdAt: updatedAt: + readAt: title: topic: members: @@ -940,6 +958,7 @@ models: resolver: true createdAt: updatedAt: + readAt: title: topic: members: diff --git a/core/api/node/graphql/graph/generated/generated.gen.go b/core/api/node/graphql/graph/generated/generated.gen.go index 64ea2c7101..4649de35b2 100644 --- a/core/api/node/graphql/graph/generated/generated.gen.go +++ b/core/api/node/graphql/graph/generated/generated.gen.go @@ -13,6 +13,7 @@ import ( node "berty.tech/core/api/node" models "berty.tech/core/api/node/graphql/models" p2p "berty.tech/core/api/p2p" + graphql1 "berty.tech/core/api/protobuf/graphql" entity "berty.tech/core/entity" network "berty.tech/core/network" deviceinfo "berty.tech/core/pkg/deviceinfo" @@ -52,6 +53,7 @@ type ResolverRoot interface { GoogleProtobufFieldOptions() GoogleProtobufFieldOptionsResolver GoogleProtobufFileOptions() GoogleProtobufFileOptionsResolver GoogleProtobufMethodOptions() GoogleProtobufMethodOptionsResolver + GqlNode() GqlNodeResolver Mutation() MutationResolver Query() QueryResolver Subscription() SubscriptionResolver @@ -91,6 +93,7 @@ type ComplexityRoot struct { Id func(childComplexity int) int CreatedAt func(childComplexity int) int UpdatedAt func(childComplexity int) int + ReadAt func(childComplexity int) int Title func(childComplexity int) int Topic func(childComplexity int) int Members func(childComplexity int) int @@ -120,6 +123,7 @@ type ComplexityRoot struct { Id func(childComplexity int) int CreatedAt func(childComplexity int) int UpdatedAt func(childComplexity int) int + ReadAt func(childComplexity int) int Title func(childComplexity int) int Topic func(childComplexity int) int Members func(childComplexity int) int @@ -639,8 +643,12 @@ type ComplexityRoot struct { IsExtension func(childComplexity int) int } + GqlNode struct { + Id func(childComplexity int) int + } + Mutation struct { - EventSeen func(childComplexity int, eventId string) int + EventSeen func(childComplexity int, id string) int ContactRequest func(childComplexity int, contact *entity.Contact, introText string) int ContactAcceptRequest 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 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 @@ -649,6 +657,7 @@ type ComplexityRoot struct { ConversationInvite func(childComplexity int, conversation *entity.Conversation, members []*entity.ConversationMember) int ConversationExclude func(childComplexity int, conversation *entity.Conversation, members []*entity.ConversationMember) int ConversationAddMessage func(childComplexity int, conversation *entity.Conversation, message *entity.Message) int + ConversationRead func(childComplexity int, id string) int GenerateFakeData func(childComplexity int, T bool) int RunIntegrationTests func(childComplexity int, name string) int DebugRequeueEvent func(childComplexity int, eventId string) int @@ -663,7 +672,7 @@ type ComplexityRoot struct { ContactList func(childComplexity int, filter *entity.Contact, orderBy string, orderDesc bool, first *int32, after *string, last *int32, before *string) int GetContact 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 ConversationList func(childComplexity int, filter *entity.Conversation, orderBy string, orderDesc bool, first *int32, after *string, last *int32, before *string) int - GetConversation func(childComplexity int, id string, createdAt *time.Time, updatedAt *time.Time, title string, topic string, members []*entity.ConversationMember) int + GetConversation func(childComplexity int, id string, createdAt *time.Time, updatedAt *time.Time, readAt *time.Time, title string, topic string, members []*entity.ConversationMember) int GetConversationMember func(childComplexity int, id string, createdAt *time.Time, updatedAt *time.Time, status *int32, contact *entity.Contact, conversationId string, contactId string) int DeviceInfos func(childComplexity int, T bool) int AppVersion func(childComplexity int, T bool) int @@ -733,8 +742,11 @@ type GoogleProtobufFileOptionsResolver interface { type GoogleProtobufMethodOptionsResolver interface { IdempotencyLevel(ctx context.Context, obj *descriptor.MethodOptions) (*int32, error) } +type GqlNodeResolver interface { + ID(ctx context.Context, obj *graphql1.Node) (string, error) +} type MutationResolver interface { - EventSeen(ctx context.Context, eventId string) (*p2p.Event, error) + EventSeen(ctx context.Context, id string) (*p2p.Event, error) ContactRequest(ctx context.Context, contact *entity.Contact, introText string) (*entity.Contact, error) ContactAcceptRequest(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) 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) @@ -743,6 +755,7 @@ type MutationResolver interface { ConversationInvite(ctx context.Context, conversation *entity.Conversation, members []*entity.ConversationMember) (*entity.Conversation, error) ConversationExclude(ctx context.Context, conversation *entity.Conversation, members []*entity.ConversationMember) (*entity.Conversation, error) ConversationAddMessage(ctx context.Context, conversation *entity.Conversation, message *entity.Message) (*p2p.Event, error) + ConversationRead(ctx context.Context, id string) (*entity.Conversation, error) GenerateFakeData(ctx context.Context, T bool) (*node.Void, error) RunIntegrationTests(ctx context.Context, name string) (*node.IntegrationTestOutput, error) DebugRequeueEvent(ctx context.Context, eventId string) (*p2p.Event, error) @@ -756,7 +769,7 @@ type QueryResolver interface { ContactList(ctx context.Context, filter *entity.Contact, orderBy string, orderDesc bool, first *int32, after *string, last *int32, before *string) (*node.ContactListConnection, error) GetContact(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) ConversationList(ctx context.Context, filter *entity.Conversation, orderBy string, orderDesc bool, first *int32, after *string, last *int32, before *string) (*node.ConversationListConnection, error) - GetConversation(ctx context.Context, id string, createdAt *time.Time, updatedAt *time.Time, title string, topic string, members []*entity.ConversationMember) (*entity.Conversation, error) + GetConversation(ctx context.Context, id string, createdAt *time.Time, updatedAt *time.Time, readAt *time.Time, title string, topic string, members []*entity.ConversationMember) (*entity.Conversation, error) GetConversationMember(ctx context.Context, id string, createdAt *time.Time, updatedAt *time.Time, status *int32, contact *entity.Contact, conversationId string, contactId string) (*entity.ConversationMember, error) DeviceInfos(ctx context.Context, T bool) (*deviceinfo.DeviceInfos, error) AppVersion(ctx context.Context, T bool) (*node.AppVersionOutput, error) @@ -776,14 +789,14 @@ type SubscriptionResolver interface { func field_Mutation_EventSeen_args(rawArgs map[string]interface{}) (map[string]interface{}, error) { args := map[string]interface{}{} var arg0 string - if tmp, ok := rawArgs["eventId"]; ok { + if tmp, ok := rawArgs["id"]; ok { var err error arg0, err = models.UnmarshalID(tmp) if err != nil { return nil, err } } - args["eventId"] = arg0 + args["id"] = arg0 return args, nil } @@ -1398,6 +1411,21 @@ func field_Mutation_ConversationAddMessage_args(rawArgs map[string]interface{}) } +func field_Mutation_ConversationRead_args(rawArgs map[string]interface{}) (map[string]interface{}, error) { + args := map[string]interface{}{} + var arg0 string + if tmp, ok := rawArgs["id"]; ok { + var err error + arg0, err = models.UnmarshalID(tmp) + if err != nil { + return nil, err + } + } + args["id"] = arg0 + return args, nil + +} + func field_Mutation_GenerateFakeData_args(rawArgs map[string]interface{}) (map[string]interface{}, error) { args := map[string]interface{}{} var arg0 bool @@ -2176,25 +2204,39 @@ func field_Query_GetConversation_args(rawArgs map[string]interface{}) (map[strin } } args["updatedAt"] = arg2 - var arg3 string - if tmp, ok := rawArgs["title"]; ok { + var arg3 *time.Time + if tmp, ok := rawArgs["readAt"]; ok { var err error - arg3, err = models.UnmarshalString(tmp) + var ptr1 time.Time + if tmp != nil { + ptr1, err = models.UnmarshalTime(tmp) + arg3 = &ptr1 + } + if err != nil { return nil, err } } - args["title"] = arg3 + args["readAt"] = arg3 var arg4 string - if tmp, ok := rawArgs["topic"]; ok { + if tmp, ok := rawArgs["title"]; ok { var err error arg4, err = models.UnmarshalString(tmp) if err != nil { return nil, err } } - args["topic"] = arg4 - var arg5 []*entity.ConversationMember + args["title"] = arg4 + var arg5 string + if tmp, ok := rawArgs["topic"]; ok { + var err error + arg5, err = models.UnmarshalString(tmp) + if err != nil { + return nil, err + } + } + args["topic"] = arg5 + var arg6 []*entity.ConversationMember if tmp, ok := rawArgs["members"]; ok { var err error var rawIf1 []interface{} @@ -2205,19 +2247,19 @@ func field_Query_GetConversation_args(rawArgs map[string]interface{}) (map[strin rawIf1 = []interface{}{tmp} } } - arg5 = make([]*entity.ConversationMember, len(rawIf1)) + arg6 = make([]*entity.ConversationMember, len(rawIf1)) for idx1 := range rawIf1 { var ptr2 entity.ConversationMember if rawIf1[idx1] != nil { ptr2, err = UnmarshalBertyEntityConversationMemberInput(rawIf1[idx1]) - arg5[idx1] = &ptr2 + arg6[idx1] = &ptr2 } } if err != nil { return nil, err } } - args["members"] = arg5 + args["members"] = arg6 return args, nil } @@ -2836,6 +2878,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.BertyEntityConversation.UpdatedAt(childComplexity), true + case "BertyEntityConversation.readAt": + if e.complexity.BertyEntityConversation.ReadAt == nil { + break + } + + return e.complexity.BertyEntityConversation.ReadAt(childComplexity), true + case "BertyEntityConversation.title": if e.complexity.BertyEntityConversation.Title == nil { break @@ -2976,6 +3025,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.BertyEntityConversationPayload.UpdatedAt(childComplexity), true + case "BertyEntityConversationPayload.readAt": + if e.complexity.BertyEntityConversationPayload.ReadAt == nil { + break + } + + return e.complexity.BertyEntityConversationPayload.ReadAt(childComplexity), true + case "BertyEntityConversationPayload.title": if e.complexity.BertyEntityConversationPayload.Title == nil { break @@ -4915,6 +4971,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.GoogleProtobufUninterpretedOptionNamePart.IsExtension(childComplexity), true + case "GqlNode.id": + if e.complexity.GqlNode.Id == nil { + break + } + + return e.complexity.GqlNode.Id(childComplexity), true + case "Mutation.EventSeen": if e.complexity.Mutation.EventSeen == nil { break @@ -4925,7 +4988,7 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return 0, false } - return e.complexity.Mutation.EventSeen(childComplexity, args["eventId"].(string)), true + return e.complexity.Mutation.EventSeen(childComplexity, args["id"].(string)), true case "Mutation.ContactRequest": if e.complexity.Mutation.ContactRequest == nil { @@ -5023,6 +5086,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Mutation.ConversationAddMessage(childComplexity, args["conversation"].(*entity.Conversation), args["message"].(*entity.Message)), true + case "Mutation.ConversationRead": + if e.complexity.Mutation.ConversationRead == nil { + break + } + + args, err := field_Mutation_ConversationRead_args(rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Mutation.ConversationRead(childComplexity, args["id"].(string)), true + case "Mutation.GenerateFakeData": if e.complexity.Mutation.GenerateFakeData == nil { break @@ -5165,7 +5240,7 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return 0, false } - return e.complexity.Query.GetConversation(childComplexity, args["id"].(string), args["createdAt"].(*time.Time), args["updatedAt"].(*time.Time), args["title"].(string), args["topic"].(string), args["members"].([]*entity.ConversationMember)), true + return e.complexity.Query.GetConversation(childComplexity, args["id"].(string), args["createdAt"].(*time.Time), args["updatedAt"].(*time.Time), args["readAt"].(*time.Time), args["title"].(string), args["topic"].(string), args["members"].([]*entity.ConversationMember)), true case "Query.GetConversationMember": if e.complexity.Query.GetConversationMember == nil { @@ -6066,6 +6141,8 @@ func (ec *executionContext) _BertyEntityConversation(ctx context.Context, sel as out.Values[i] = ec._BertyEntityConversation_createdAt(ctx, field, obj) case "updatedAt": out.Values[i] = ec._BertyEntityConversation_updatedAt(ctx, field, obj) + case "readAt": + out.Values[i] = ec._BertyEntityConversation_readAt(ctx, field, obj) case "title": out.Values[i] = ec._BertyEntityConversation_title(ctx, field, obj) if out.Values[i] == graphql.Null { @@ -6152,6 +6229,26 @@ func (ec *executionContext) _BertyEntityConversation_updatedAt(ctx context.Conte return models.MarshalTime(res) } +// nolint: vetshadow +func (ec *executionContext) _BertyEntityConversation_readAt(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.ReadAt, 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{ @@ -6697,6 +6794,8 @@ func (ec *executionContext) _BertyEntityConversationPayload(ctx context.Context, out.Values[i] = ec._BertyEntityConversationPayload_createdAt(ctx, field, obj) case "updatedAt": out.Values[i] = ec._BertyEntityConversationPayload_updatedAt(ctx, field, obj) + case "readAt": + out.Values[i] = ec._BertyEntityConversationPayload_readAt(ctx, field, obj) case "title": out.Values[i] = ec._BertyEntityConversationPayload_title(ctx, field, obj) if out.Values[i] == graphql.Null { @@ -6783,6 +6882,26 @@ func (ec *executionContext) _BertyEntityConversationPayload_updatedAt(ctx contex return models.MarshalTime(res) } +// nolint: vetshadow +func (ec *executionContext) _BertyEntityConversationPayload_readAt(ctx context.Context, field graphql.CollectedField, obj *entity.Conversation) graphql.Marshaler { + rctx := &graphql.ResolverContext{ + Object: "BertyEntityConversationPayload", + 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.ReadAt, nil + }) + if resTmp == nil { + return graphql.Null + } + res := resTmp.(time.Time) + rctx.Result = res + return models.MarshalTime(res) +} + // nolint: vetshadow func (ec *executionContext) _BertyEntityConversationPayload_title(ctx context.Context, field graphql.CollectedField, obj *entity.Conversation) graphql.Marshaler { rctx := &graphql.ResolverContext{ @@ -18068,6 +18187,64 @@ func (ec *executionContext) _GoogleProtobufUninterpretedOptionNamePart_isExtensi return models.MarshalBool(*res) } +var gqlNodeImplementors = []string{"GqlNode", "Node"} + +// nolint: gocyclo, errcheck, gas, goconst +func (ec *executionContext) _GqlNode(ctx context.Context, sel ast.SelectionSet, obj *graphql1.Node) graphql.Marshaler { + fields := graphql.CollectFields(ctx, sel, gqlNodeImplementors) + + var wg sync.WaitGroup + out := graphql.NewOrderedMap(len(fields)) + invalid := false + for i, field := range fields { + out.Keys[i] = field.Alias + + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("GqlNode") + case "id": + wg.Add(1) + go func(i int, field graphql.CollectedField) { + out.Values[i] = ec._GqlNode_id(ctx, field, obj) + if out.Values[i] == graphql.Null { + invalid = true + } + wg.Done() + }(i, field) + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + wg.Wait() + if invalid { + return graphql.Null + } + return out +} + +// nolint: vetshadow +func (ec *executionContext) _GqlNode_id(ctx context.Context, field graphql.CollectedField, obj *graphql1.Node) graphql.Marshaler { + rctx := &graphql.ResolverContext{ + Object: "GqlNode", + 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 ec.resolvers.GqlNode().ID(rctx, obj) + }) + if resTmp == nil { + if !ec.HasError(rctx) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + rctx.Result = res + return models.MarshalID(res) +} + var mutationImplementors = []string{"Mutation"} // nolint: gocyclo, errcheck, gas, goconst @@ -18104,6 +18281,8 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet) out.Values[i] = ec._Mutation_ConversationExclude(ctx, field) case "ConversationAddMessage": out.Values[i] = ec._Mutation_ConversationAddMessage(ctx, field) + case "ConversationRead": + out.Values[i] = ec._Mutation_ConversationRead(ctx, field) case "GenerateFakeData": out.Values[i] = ec._Mutation_GenerateFakeData(ctx, field) case "RunIntegrationTests": @@ -18139,7 +18318,7 @@ func (ec *executionContext) _Mutation_EventSeen(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.Mutation().EventSeen(rctx, args["eventId"].(string)) + return ec.resolvers.Mutation().EventSeen(rctx, args["id"].(string)) }) if resTmp == nil { return graphql.Null @@ -18402,6 +18581,37 @@ func (ec *executionContext) _Mutation_ConversationAddMessage(ctx context.Context return ec._BertyP2pEventPayload(ctx, field.Selections, res) } +// nolint: vetshadow +func (ec *executionContext) _Mutation_ConversationRead(ctx context.Context, field graphql.CollectedField) graphql.Marshaler { + rawArgs := field.ArgumentMap(ec.Variables) + args, err := field_Mutation_ConversationRead_args(rawArgs) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + rctx := &graphql.ResolverContext{ + Object: "Mutation", + Args: args, + Field: 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.Mutation().ConversationRead(rctx, args["id"].(string)) + }) + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*entity.Conversation) + rctx.Result = res + + if res == nil { + return graphql.Null + } + + return ec._BertyEntityConversationPayload(ctx, field.Selections, res) +} + // nolint: vetshadow func (ec *executionContext) _Mutation_GenerateFakeData(ctx context.Context, field graphql.CollectedField) graphql.Marshaler { rawArgs := field.ArgumentMap(ec.Variables) @@ -18879,7 +19089,7 @@ func (ec *executionContext) _Query_GetConversation(ctx context.Context, field gr 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().GetConversation(rctx, args["id"].(string), args["createdAt"].(*time.Time), args["updatedAt"].(*time.Time), args["title"].(string), args["topic"].(string), args["members"].([]*entity.ConversationMember)) + return ec.resolvers.Query().GetConversation(rctx, args["id"].(string), args["createdAt"].(*time.Time), args["updatedAt"].(*time.Time), args["readAt"].(*time.Time), args["title"].(string), args["topic"].(string), args["members"].([]*entity.ConversationMember)) }) if resTmp == nil { return graphql.Null @@ -20706,6 +20916,8 @@ func (ec *executionContext) _Node(ctx context.Context, sel ast.SelectionSet, obj switch obj := (*obj).(type) { case nil: return graphql.Null + case *graphql1.Node: + return ec._GqlNode(ctx, sel, obj) case entity.Device: return ec._BertyEntityDevice(ctx, sel, &obj) case *entity.Device: @@ -20856,6 +21068,12 @@ func UnmarshalBertyEntityConversationInput(v interface{}) (entity.Conversation, if err != nil { return it, err } + case "readAt": + var err error + it.ReadAt, err = models.UnmarshalTime(v) + if err != nil { + return it, err + } case "title": var err error it.Title, err = models.UnmarshalString(v) @@ -21604,6 +21822,7 @@ type BertyEntityConversation implements Node { id: ID! createdAt: GoogleProtobufTimestamp updatedAt: GoogleProtobufTimestamp + readAt: GoogleProtobufTimestamp title: String! topic: String! members: [BertyEntityConversationMember] @@ -21896,6 +22115,7 @@ type BertyEntityConversationPayload { id: ID! createdAt: GoogleProtobufTimestamp updatedAt: GoogleProtobufTimestamp + readAt: GoogleProtobufTimestamp title: String! topic: String! members: [BertyEntityConversationMember] @@ -21913,6 +22133,7 @@ input BertyEntityConversationInput { id: ID! createdAt: GoogleProtobufTimestampInput updatedAt: GoogleProtobufTimestampInput + readAt: GoogleProtobufTimestampInput title: String! topic: String! members: [BertyEntityConversationMemberInput] @@ -22036,6 +22257,7 @@ type Query { id: ID! createdAt: GoogleProtobufTimestampInput updatedAt: GoogleProtobufTimestampInput + readAt: GoogleProtobufTimestampInput title: String! topic: String! members: [BertyEntityConversationMemberInput] @@ -22073,7 +22295,7 @@ type Query { type Mutation { EventSeen( - eventId: ID! + id: ID! ): BertyP2pEventPayload ContactRequest( contact: BertyEntityContactInput @@ -22132,6 +22354,9 @@ type Mutation { conversation: BertyEntityConversationInput message: BertyEntityMessageInput ): BertyP2pEventPayload + ConversationRead( + id: ID! + ): BertyEntityConversationPayload GenerateFakeData( T: Bool! ): BertyNodeVoidPayload diff --git a/core/api/node/graphql/resolver.go b/core/api/node/graphql/resolver.go index f9a0beda9d..0ad06c0194 100644 --- a/core/api/node/graphql/resolver.go +++ b/core/api/node/graphql/resolver.go @@ -15,6 +15,7 @@ import ( "berty.tech/core/api/node/graphql/graph/generated" "berty.tech/core/api/node/graphql/models" "berty.tech/core/api/p2p" + gql "berty.tech/core/api/protobuf/graphql" "berty.tech/core/entity" "berty.tech/core/network" "berty.tech/core/pkg/deviceinfo" @@ -29,7 +30,9 @@ func New(client node.ServiceClient) generated.Config { Resolvers: &Resolver{client}, } } - +func (r *Resolver) GqlNode() generated.GqlNodeResolver { + return &gqlNodeResolver{r} +} func (r *Resolver) BertyEntityContact() generated.BertyEntityContactResolver { return &bertyEntityContactResolver{r} } @@ -87,6 +90,13 @@ func (r *Resolver) Subscription() generated.SubscriptionResolver { return &subscriptionResolver{r} } +type gqlNodeResolver struct{ *Resolver } + +func (r *gqlNodeResolver) ID(ctx context.Context, obj *gql.Node) (string, error) { + // TODO: find the id in db to define the table + return "unknown:" + obj.ID, nil +} + type bertyEntityContactResolver struct{ *Resolver } func (r *bertyEntityContactResolver) ID(ctx context.Context, obj *entity.Contact) (string, error) { @@ -386,11 +396,11 @@ func (r *queryResolver) GetEvent(ctx context.Context, id string, senderID string }) } -func (r *mutationResolver) EventSeen(ctx context.Context, eventID string) (*p2p.Event, error) { - eventID = strings.SplitN(eventID, ":", 2)[1] +func (r *mutationResolver) EventSeen(ctx context.Context, id string) (*p2p.Event, error) { + id = strings.SplitN(id, ":", 2)[1] - return r.client.EventSeen(ctx, &node.EventIDInput{ - EventID: eventID, + return r.client.EventSeen(ctx, &gql.Node{ + ID: id, }) } @@ -533,7 +543,15 @@ func (r *queryResolver) ConversationList(ctx context.Context, filter *entity.Con output.PageInfo.HasNextPage = hasNextPage return output, nil } -func (r *queryResolver) GetConversation(ctx context.Context, id string, createdAt *time.Time, updatedAt *time.Time, title string, topic string, members []*entity.ConversationMember) (*entity.Conversation, error) { +func (r *mutationResolver) ConversationRead(ctx context.Context, id string) (*entity.Conversation, error) { + id = strings.SplitN(id, ":", 2)[1] + + return r.client.ConversationRead(ctx, &gql.Node{ + ID: id, + }) +} + +func (r *queryResolver) GetConversation(ctx context.Context, id string, createdAt *time.Time, updatedAt *time.Time, readAt *time.Time, title string, topic string, members []*entity.ConversationMember) (*entity.Conversation, error) { return r.client.GetConversation(ctx, &entity.Conversation{ID: id}) } func (r *queryResolver) GetConversationMember(ctx context.Context, id string, createdAt *time.Time, updatedAt *time.Time, status *int32, contact *entity.Contact, conversationID string, contactID string) (*entity.ConversationMember, error) { diff --git a/core/api/node/graphql/service.gen.graphql b/core/api/node/graphql/service.gen.graphql index 7c6941ce7d..293d195a6c 100644 --- a/core/api/node/graphql/service.gen.graphql +++ b/core/api/node/graphql/service.gen.graphql @@ -303,6 +303,7 @@ type BertyEntityConversation implements Node { id: ID! createdAt: GoogleProtobufTimestamp updatedAt: GoogleProtobufTimestamp + readAt: GoogleProtobufTimestamp title: String! topic: String! members: [BertyEntityConversationMember] @@ -595,6 +596,7 @@ type BertyEntityConversationPayload { id: ID! createdAt: GoogleProtobufTimestamp updatedAt: GoogleProtobufTimestamp + readAt: GoogleProtobufTimestamp title: String! topic: String! members: [BertyEntityConversationMember] @@ -612,6 +614,7 @@ input BertyEntityConversationInput { id: ID! createdAt: GoogleProtobufTimestampInput updatedAt: GoogleProtobufTimestampInput + readAt: GoogleProtobufTimestampInput title: String! topic: String! members: [BertyEntityConversationMemberInput] @@ -735,6 +738,7 @@ type Query { id: ID! createdAt: GoogleProtobufTimestampInput updatedAt: GoogleProtobufTimestampInput + readAt: GoogleProtobufTimestampInput title: String! topic: String! members: [BertyEntityConversationMemberInput] @@ -772,7 +776,7 @@ type Query { type Mutation { EventSeen( - eventId: ID! + id: ID! ): BertyP2pEventPayload ContactRequest( contact: BertyEntityContactInput @@ -831,6 +835,9 @@ type Mutation { conversation: BertyEntityConversationInput message: BertyEntityMessageInput ): BertyP2pEventPayload + ConversationRead( + id: ID! + ): BertyEntityConversationPayload GenerateFakeData( T: Bool! ): BertyNodeVoidPayload diff --git a/core/api/node/service.proto b/core/api/node/service.proto index c31891525e..fb1e19eba7 100644 --- a/core/api/node/service.proto +++ b/core/api/node/service.proto @@ -94,6 +94,9 @@ service Service { rpc GetConversationMember (berty.entity.ConversationMember) returns (berty.entity.ConversationMember) { option (gql.graphql_type) = "Query"; }; + rpc ConversationRead (gql.Node) returns (berty.entity.Conversation) { + option (gql.graphql_type) = "Mutation"; + } //rpc ConversationLeave(berty.entity.Conversation) returns (berty.entity.Conversation); //rpc ConversationJoinRequest(berty.entity.Conversation) returns (berty.entity.Conversation); @@ -201,6 +204,9 @@ message EventStreamInput { } +// Node + + // // EventList // @@ -361,3 +367,4 @@ message NodeEvent { // Attributes is a nested protobuf message containing per-event-type additional attributes. bytes attributes = 2; } + diff --git a/core/api/protobuf/graphql/graphql.go b/core/api/protobuf/graphql/graphql.go new file mode 100644 index 0000000000..d8d6bee3e9 --- /dev/null +++ b/core/api/protobuf/graphql/graphql.go @@ -0,0 +1,5 @@ +package graphql + +func (n *Node) IsNode() { + return +} diff --git a/core/api/protobuf/graphql/graphql.pb.go b/core/api/protobuf/graphql/graphql.pb.go index 8400f1e0d4..ac0ee6d706 100644 --- a/core/api/protobuf/graphql/graphql.pb.go +++ b/core/api/protobuf/graphql/graphql.pb.go @@ -6,8 +6,11 @@ package graphql // import "berty.tech/core/api/protobuf/graphql" import proto "github.com/golang/protobuf/proto" import fmt "fmt" import math "math" +import _ "github.com/gogo/protobuf/gogoproto" import descriptor "github.com/golang/protobuf/protoc-gen-go/descriptor" +import io "io" + // Reference imports to suppress errors if they are not otherwise used. var _ = proto.Marshal var _ = fmt.Errorf @@ -19,6 +22,53 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package +type Node struct { + ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Node) Reset() { *m = Node{} } +func (m *Node) String() string { return proto.CompactTextString(m) } +func (*Node) ProtoMessage() {} +func (*Node) Descriptor() ([]byte, []int) { + return fileDescriptor_graphql_23670d604dbebb79, []int{0} +} +func (m *Node) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Node) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Node.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalTo(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (dst *Node) XXX_Merge(src proto.Message) { + xxx_messageInfo_Node.Merge(dst, src) +} +func (m *Node) XXX_Size() int { + return m.Size() +} +func (m *Node) XXX_DiscardUnknown() { + xxx_messageInfo_Node.DiscardUnknown(m) +} + +var xxx_messageInfo_Node proto.InternalMessageInfo + +func (m *Node) GetID() string { + if m != nil { + return m.ID + } + return "" +} + var E_GraphqlFields = &proto.ExtensionDesc{ ExtendedType: (*descriptor.MethodOptions)(nil), ExtensionType: (*string)(nil), @@ -101,6 +151,7 @@ var E_GraphqlNonNullable = &proto.ExtensionDesc{ } func init() { + proto.RegisterType((*Node)(nil), "gql.Node") proto.RegisterExtension(E_GraphqlFields) proto.RegisterExtension(E_GraphqlType) proto.RegisterExtension(E_GraphqlInterface) @@ -111,33 +162,285 @@ func init() { proto.RegisterExtension(E_GraphqlNullable) proto.RegisterExtension(E_GraphqlNonNullable) } +func (m *Node) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Node) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if len(m.ID) > 0 { + dAtA[i] = 0xa + i++ + i = encodeVarintGraphql(dAtA, i, uint64(len(m.ID))) + i += copy(dAtA[i:], m.ID) + } + if m.XXX_unrecognized != nil { + i += copy(dAtA[i:], m.XXX_unrecognized) + } + return i, nil +} + +func encodeVarintGraphql(dAtA []byte, offset int, v uint64) int { + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return offset + 1 +} +func (m *Node) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ID) + if l > 0 { + n += 1 + l + sovGraphql(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func sovGraphql(x uint64) (n int) { + for { + n++ + x >>= 7 + if x == 0 { + break + } + } + return n +} +func sozGraphql(x uint64) (n int) { + return sovGraphql(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *Node) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGraphql + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Node: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Node: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ID", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGraphql + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGraphql + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ID = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGraphql(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthGraphql + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipGraphql(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGraphql + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGraphql + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + return iNdEx, nil + case 1: + iNdEx += 8 + return iNdEx, nil + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGraphql + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + iNdEx += length + if length < 0 { + return 0, ErrInvalidLengthGraphql + } + return iNdEx, nil + case 3: + for { + var innerWire uint64 + var start int = iNdEx + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGraphql + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + innerWire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + innerWireType := int(innerWire & 0x7) + if innerWireType == 4 { + break + } + next, err := skipGraphql(dAtA[start:]) + if err != nil { + return 0, err + } + iNdEx = start + next + } + return iNdEx, nil + case 4: + return iNdEx, nil + case 5: + iNdEx += 4 + return iNdEx, nil + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + } + panic("unreachable") +} + +var ( + ErrInvalidLengthGraphql = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowGraphql = fmt.Errorf("proto: integer overflow") +) func init() { - proto.RegisterFile("api/protobuf/graphql/graphql.proto", fileDescriptor_graphql_bdc8fca1dcb0fa6d) -} - -var fileDescriptor_graphql_bdc8fca1dcb0fa6d = []byte{ - // 341 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0xd3, 0x3d, 0x4b, 0xc3, 0x40, - 0x18, 0xc0, 0x71, 0x43, 0x41, 0xec, 0xf9, 0x1e, 0x1c, 0x44, 0x30, 0x14, 0x71, 0x70, 0x4a, 0x06, - 0xc1, 0xe1, 0x06, 0x07, 0x85, 0x8a, 0x42, 0x2d, 0x56, 0x27, 0x97, 0x92, 0x97, 0xa7, 0x69, 0xe0, - 0xc8, 0x5d, 0x2f, 0x17, 0xa1, 0x1f, 0xc1, 0x77, 0xdd, 0x9c, 0xfc, 0x3c, 0x8e, 0x7e, 0x04, 0x89, - 0x5f, 0x44, 0xb8, 0x3e, 0xd7, 0x96, 0x2a, 0x9c, 0x53, 0x20, 0xb9, 0xff, 0x8f, 0xe7, 0x09, 0x1c, - 0xd9, 0x09, 0x45, 0x16, 0x08, 0xc9, 0x15, 0x8f, 0xca, 0x5e, 0x90, 0xca, 0x50, 0xf4, 0x07, 0xcc, - 0x3c, 0x7d, 0xfd, 0xc1, 0xad, 0xa5, 0x03, 0xb6, 0xd5, 0x48, 0x39, 0x4f, 0x19, 0x4c, 0xce, 0x26, - 0x50, 0xc4, 0x32, 0x13, 0x8a, 0xcb, 0xd1, 0x31, 0x7a, 0x42, 0x56, 0xb0, 0xeb, 0xf6, 0x32, 0x60, - 0x49, 0xe1, 0x7a, 0xfe, 0x28, 0xf2, 0x4d, 0xe4, 0xb7, 0x40, 0xf5, 0x79, 0xd2, 0x16, 0x2a, 0xe3, - 0x79, 0xb1, 0x79, 0xfb, 0x5e, 0x6b, 0x38, 0x7b, 0xf5, 0xce, 0x32, 0x76, 0x4d, 0x9d, 0xd1, 0x63, - 0xb2, 0x64, 0x20, 0x35, 0x14, 0x60, 0x65, 0xee, 0x90, 0x59, 0xc4, 0xea, 0x6a, 0x28, 0x80, 0xb6, - 0xc8, 0xba, 0x41, 0xb2, 0x5c, 0x81, 0xec, 0x85, 0xb1, 0x5d, 0xba, 0x47, 0x69, 0x0d, 0xd3, 0x53, - 0x53, 0x4e, 0x2f, 0xc7, 0x4b, 0x25, 0x4a, 0x65, 0xb5, 0x9e, 0x67, 0x96, 0x6b, 0xeb, 0x8c, 0x1e, - 0x12, 0x32, 0x9e, 0x2b, 0x71, 0xb7, 0x7f, 0x21, 0xfa, 0x1f, 0x18, 0xe3, 0x41, 0x1b, 0x0b, 0x9d, - 0xba, 0x99, 0x27, 0xa1, 0x67, 0xc4, 0x0c, 0xd7, 0x95, 0x50, 0x70, 0x76, 0x03, 0xd2, 0xa6, 0x3c, - 0xa2, 0xb2, 0x8a, 0x61, 0x07, 0x3b, 0xda, 0x9c, 0x2c, 0x55, 0x08, 0x09, 0xa1, 0x75, 0x9e, 0x27, - 0x94, 0xcc, 0x4e, 0x97, 0xba, 0x9a, 0x9e, 0x29, 0x2f, 0x19, 0x0b, 0x23, 0x06, 0x36, 0xe9, 0x65, - 0x66, 0xa6, 0x73, 0xec, 0xe8, 0x05, 0xd9, 0x18, 0x5b, 0x3c, 0xff, 0xb7, 0xf7, 0x8a, 0x9e, 0x6b, - 0x3c, 0x9e, 0x1b, 0xf2, 0xe8, 0xe0, 0xa3, 0xf2, 0x9c, 0xcf, 0xca, 0x73, 0xbe, 0x2a, 0xcf, 0x79, - 0xfb, 0xf6, 0xe6, 0xae, 0x77, 0x23, 0x90, 0x6a, 0xe8, 0x2b, 0x88, 0xfb, 0x41, 0xcc, 0x25, 0x04, - 0x7f, 0xdd, 0x82, 0x68, 0x5e, 0xbf, 0xd9, 0xff, 0x09, 0x00, 0x00, 0xff, 0xff, 0x48, 0x46, 0x0f, - 0x8c, 0x24, 0x03, 0x00, 0x00, + proto.RegisterFile("api/protobuf/graphql/graphql.proto", fileDescriptor_graphql_23670d604dbebb79) +} + +var fileDescriptor_graphql_23670d604dbebb79 = []byte{ + // 387 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0xd3, 0xcf, 0x4a, 0xc3, 0x30, + 0x1c, 0x07, 0x70, 0xbb, 0x89, 0xb8, 0xf8, 0xbf, 0xec, 0x30, 0x07, 0xd6, 0x31, 0x3c, 0x78, 0x6a, + 0x0f, 0x82, 0x87, 0x1e, 0x3c, 0x4c, 0x99, 0x4c, 0xd8, 0x86, 0xd5, 0x93, 0x97, 0xd1, 0x36, 0x59, + 0x57, 0x08, 0x4d, 0x96, 0xa6, 0xc2, 0x1e, 0xc1, 0xff, 0x7a, 0xf3, 0xe4, 0xf3, 0x78, 0xf4, 0x09, + 0x64, 0xd4, 0x17, 0xf0, 0x11, 0x64, 0x59, 0xb2, 0x8d, 0x29, 0xd4, 0x53, 0x43, 0x9a, 0xef, 0x27, + 0xdf, 0x5f, 0xa1, 0xa0, 0xea, 0xd2, 0xd0, 0xa2, 0x8c, 0x70, 0xe2, 0x25, 0x5d, 0x2b, 0x60, 0x2e, + 0xed, 0xf5, 0xb1, 0x7a, 0x9a, 0xe2, 0x85, 0x9e, 0x0f, 0xfa, 0xb8, 0x5c, 0x09, 0x08, 0x09, 0x30, + 0x9a, 0x9e, 0x85, 0x28, 0xf6, 0x59, 0x48, 0x39, 0x61, 0xe3, 0x63, 0xe5, 0x62, 0x40, 0x02, 0x22, + 0x96, 0xd6, 0x68, 0x35, 0xde, 0xad, 0x56, 0xc1, 0x62, 0x8b, 0x40, 0xa4, 0x97, 0x41, 0x2e, 0x84, + 0x25, 0xad, 0xa2, 0xed, 0x17, 0x6a, 0x60, 0xf8, 0xbd, 0xad, 0xa5, 0x9f, 0xbb, 0xb9, 0xc6, 0x89, + 0x93, 0x0b, 0xa1, 0x7d, 0x0a, 0xd6, 0xe5, 0x8d, 0x9d, 0x6e, 0x88, 0x30, 0x8c, 0x75, 0xc3, 0x1c, + 0x5f, 0x67, 0xaa, 0xeb, 0xcc, 0x26, 0xe2, 0x3d, 0x02, 0xdb, 0x94, 0x87, 0x24, 0x8a, 0x4b, 0x37, + 0x6f, 0xf9, 0x91, 0xe4, 0xac, 0xc9, 0x5c, 0x5d, 0xc4, 0xec, 0x63, 0xb0, 0xaa, 0x20, 0x3e, 0xa0, + 0x28, 0x93, 0xb9, 0x95, 0xcc, 0x8a, 0x4c, 0x5d, 0x0e, 0x28, 0xb2, 0x9b, 0x60, 0x4b, 0x21, 0x61, + 0xc4, 0x11, 0xeb, 0xba, 0x7e, 0xb6, 0x74, 0x27, 0xa5, 0x4d, 0x19, 0x6d, 0xa8, 0xe4, 0xec, 0x70, + 0x24, 0xe1, 0x34, 0xe1, 0x99, 0xd6, 0xd3, 0xdc, 0x70, 0x6d, 0x11, 0xb3, 0x8f, 0x00, 0x98, 0xf4, + 0x82, 0xfa, 0xce, 0x2f, 0x44, 0x7c, 0x03, 0x65, 0xdc, 0x0b, 0x63, 0xd9, 0x29, 0xa8, 0x3e, 0xd0, + 0x3e, 0x03, 0xaa, 0x5c, 0x87, 0xa1, 0x98, 0xe0, 0x6b, 0xc4, 0xb2, 0x94, 0x07, 0xa9, 0x6c, 0xc8, + 0xa0, 0x23, 0x73, 0x76, 0x7d, 0x3a, 0x54, 0x4c, 0x19, 0x72, 0x33, 0xfb, 0x3c, 0x4a, 0x49, 0xcd, + 0x74, 0x21, 0x52, 0xb3, 0x9d, 0xa2, 0x04, 0x63, 0xd7, 0xc3, 0x28, 0x4b, 0x7a, 0x9e, 0xeb, 0xd4, + 0x92, 0x39, 0xfb, 0x1c, 0x14, 0x27, 0x16, 0x89, 0xfe, 0xed, 0xbd, 0x48, 0x4f, 0x57, 0x1e, 0x89, + 0x14, 0x59, 0x3b, 0x7c, 0x4f, 0x0d, 0xed, 0x23, 0x35, 0xb4, 0x61, 0x6a, 0x68, 0xaf, 0x5f, 0xc6, + 0xc2, 0xd5, 0x9e, 0x87, 0x18, 0x1f, 0x98, 0x1c, 0xf9, 0x3d, 0xcb, 0x27, 0x0c, 0x59, 0x7f, 0xfd, + 0x3f, 0xde, 0x92, 0xd8, 0x39, 0xf8, 0x09, 0x00, 0x00, 0xff, 0xff, 0x3a, 0x1a, 0xbb, 0x65, 0x5e, + 0x03, 0x00, 0x00, } diff --git a/core/api/protobuf/graphql/graphql.proto b/core/api/protobuf/graphql/graphql.proto index 9dd810a945..f67e5ddbdd 100644 --- a/core/api/protobuf/graphql/graphql.proto +++ b/core/api/protobuf/graphql/graphql.proto @@ -3,6 +3,7 @@ syntax = "proto3"; package gql; import "google/protobuf/descriptor.proto"; +import "gogoproto/gogo.proto"; option go_package = "berty.tech/core/api/protobuf/graphql"; @@ -20,3 +21,7 @@ extend google.protobuf.FieldOptions { bool graphql_nullable = 53008; bool graphql_non_nullable = 53009; } + +message Node { + string id = 1 [(gql.graphql_id) = true, (gogoproto.customname) = "ID"]; +} diff --git a/core/entity/conversation.pb.go b/core/entity/conversation.pb.go index 632db57a50..453f104867 100644 --- a/core/entity/conversation.pb.go +++ b/core/entity/conversation.pb.go @@ -54,13 +54,14 @@ func (x ConversationMember_Status) String() string { return proto.EnumName(ConversationMember_Status_name, int32(x)) } func (ConversationMember_Status) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_conversation_449f60adfd7d84bd, []int{1, 0} + return fileDescriptor_conversation_51d7f1b4387b1405, []int{1, 0} } type Conversation struct { ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty" gorm:"primary_key"` CreatedAt time.Time `protobuf:"bytes,2,opt,name=created_at,json=createdAt,stdtime" json:"created_at"` UpdatedAt time.Time `protobuf:"bytes,3,opt,name=updated_at,json=updatedAt,stdtime" json:"updated_at"` + ReadAt time.Time `protobuf:"bytes,4,opt,name=read_at,json=readAt,stdtime" json:"read_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"` Members []*ConversationMember `protobuf:"bytes,100,rep,name=members" json:"members,omitempty"` @@ -73,7 +74,7 @@ func (m *Conversation) Reset() { *m = Conversation{} } func (m *Conversation) String() string { return proto.CompactTextString(m) } func (*Conversation) ProtoMessage() {} func (*Conversation) Descriptor() ([]byte, []int) { - return fileDescriptor_conversation_449f60adfd7d84bd, []int{0} + return fileDescriptor_conversation_51d7f1b4387b1405, []int{0} } func (m *Conversation) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -123,6 +124,13 @@ func (m *Conversation) GetUpdatedAt() time.Time { return time.Time{} } +func (m *Conversation) GetReadAt() time.Time { + if m != nil { + return m.ReadAt + } + return time.Time{} +} + func (m *Conversation) GetTitle() string { if m != nil { return m.Title @@ -161,7 +169,7 @@ func (m *ConversationMember) Reset() { *m = ConversationMember{} } func (m *ConversationMember) String() string { return proto.CompactTextString(m) } func (*ConversationMember) ProtoMessage() {} func (*ConversationMember) Descriptor() ([]byte, []int) { - return fileDescriptor_conversation_449f60adfd7d84bd, []int{1} + return fileDescriptor_conversation_51d7f1b4387b1405, []int{1} } func (m *ConversationMember) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -281,6 +289,14 @@ func (m *Conversation) MarshalTo(dAtA []byte) (int, error) { return 0, err } i += n2 + dAtA[i] = 0x22 + i++ + i = encodeVarintConversation(dAtA, i, uint64(github_com_gogo_protobuf_types.SizeOfStdTime(m.ReadAt))) + n3, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.ReadAt, dAtA[i:]) + if err != nil { + return 0, err + } + i += n3 if len(m.Title) > 0 { dAtA[i] = 0xa2 i++ @@ -341,19 +357,19 @@ 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))) - n3, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.CreatedAt, dAtA[i:]) + n4, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.CreatedAt, dAtA[i:]) if err != nil { return 0, err } - i += n3 + i += n4 dAtA[i] = 0x1a i++ i = encodeVarintConversation(dAtA, i, uint64(github_com_gogo_protobuf_types.SizeOfStdTime(m.UpdatedAt))) - n4, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.UpdatedAt, dAtA[i:]) + n5, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.UpdatedAt, dAtA[i:]) if err != nil { return 0, err } - i += n4 + i += n5 if m.Status != 0 { dAtA[i] = 0x50 i++ @@ -365,11 +381,11 @@ func (m *ConversationMember) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0x6 i++ i = encodeVarintConversation(dAtA, i, uint64(m.Contact.Size())) - n5, err := m.Contact.MarshalTo(dAtA[i:]) + n6, err := m.Contact.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n5 + i += n6 } if len(m.ConversationID) > 0 { dAtA[i] = 0xaa @@ -416,6 +432,8 @@ func (m *Conversation) Size() (n int) { n += 1 + l + sovConversation(uint64(l)) l = github_com_gogo_protobuf_types.SizeOfStdTime(m.UpdatedAt) n += 1 + l + sovConversation(uint64(l)) + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.ReadAt) + n += 1 + l + sovConversation(uint64(l)) l = len(m.Title) if l > 0 { n += 2 + l + sovConversation(uint64(l)) @@ -602,6 +620,36 @@ func (m *Conversation) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ReadAt", 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.ReadAt, 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) @@ -1069,40 +1117,41 @@ var ( ) func init() { - proto.RegisterFile("entity/conversation.proto", fileDescriptor_conversation_449f60adfd7d84bd) + proto.RegisterFile("entity/conversation.proto", fileDescriptor_conversation_51d7f1b4387b1405) } -var fileDescriptor_conversation_449f60adfd7d84bd = []byte{ - // 489 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x93, 0x3f, 0x6f, 0xd3, 0x40, - 0x18, 0xc6, 0x73, 0x8e, 0x9a, 0x90, 0x37, 0x25, 0x44, 0xa7, 0x14, 0xb9, 0x19, 0x62, 0xcb, 0x0b, - 0x19, 0x90, 0x8d, 0xc2, 0x44, 0x19, 0x50, 0xd2, 0x2c, 0x19, 0x10, 0x92, 0x81, 0x85, 0x25, 0x72, - 0x7c, 0x57, 0xf7, 0x94, 0xd8, 0x67, 0xce, 0x6f, 0x5a, 0xe5, 0x5b, 0x30, 0xf2, 0x39, 0xf8, 0x14, - 0x1d, 0xf9, 0x04, 0xa6, 0x32, 0x0b, 0x23, 0xe2, 0x13, 0x20, 0xff, 0x53, 0x2d, 0x75, 0x40, 0x8c, - 0x9d, 0x7c, 0xf7, 0xbe, 0xcf, 0xef, 0xbd, 0xe7, 0x1e, 0xdb, 0x70, 0xca, 0x23, 0x14, 0x78, 0x70, - 0x7c, 0x19, 0x5d, 0x71, 0x95, 0x78, 0x28, 0x64, 0x64, 0xc7, 0x4a, 0xa2, 0xa4, 0xc7, 0x1b, 0xae, - 0xf0, 0x60, 0x97, 0x82, 0xb1, 0xe5, 0xc5, 0xc2, 0x29, 0x1a, 0x9b, 0xfd, 0x85, 0x13, 0x28, 0x2f, - 0xbe, 0xfc, 0xbc, 0xab, 0x9f, 0x25, 0x31, 0x1e, 0x05, 0x32, 0x90, 0xc5, 0xd2, 0xc9, 0x57, 0x55, - 0xd5, 0x08, 0xa4, 0x0c, 0x76, 0xfc, 0x0e, 0x46, 0x11, 0xf2, 0x04, 0xbd, 0x30, 0xae, 0xb1, 0x3b, - 0x0f, 0xe8, 0xf9, 0x58, 0x56, 0xad, 0x6f, 0x1a, 0x1c, 0x9f, 0x37, 0x5c, 0xd1, 0x17, 0xa0, 0x09, - 0xa6, 0x13, 0x93, 0x4c, 0x7b, 0x0b, 0xf3, 0xf6, 0xf7, 0x29, 0xc9, 0x52, 0x43, 0x5b, 0x2d, 0xff, - 0xa4, 0x06, 0x0d, 0xa4, 0x0a, 0xcf, 0xac, 0x58, 0x89, 0xd0, 0x53, 0x87, 0xf5, 0x96, 0x1f, 0x2c, - 0x57, 0x13, 0x8c, 0x9e, 0x03, 0xf8, 0x8a, 0x7b, 0xc8, 0xd9, 0xda, 0x43, 0x5d, 0x33, 0xc9, 0xb4, - 0x3f, 0x1b, 0xdb, 0xa5, 0x1d, 0xbb, 0xb6, 0x63, 0x7f, 0xa8, 0xed, 0x2c, 0x1e, 0xdd, 0xa4, 0x46, - 0xeb, 0xcb, 0x0f, 0x83, 0xb8, 0xbd, 0x8a, 0x9b, 0x63, 0x3e, 0x64, 0x1f, 0xb3, 0x7a, 0x48, 0xfb, - 0x7f, 0x86, 0x54, 0xdc, 0x1c, 0xe9, 0x08, 0x8e, 0x50, 0xe0, 0x8e, 0xeb, 0xa3, 0xdc, 0xbe, 0x5b, - 0x6e, 0x8a, 0xaa, 0x8c, 0x85, 0xaf, 0x9f, 0x54, 0xd5, 0x7c, 0x43, 0xcf, 0xa0, 0x1b, 0xf2, 0x70, - 0xc3, 0x55, 0xa2, 0x33, 0xb3, 0x3d, 0xed, 0xcf, 0x4c, 0xbb, 0xf9, 0x26, 0xec, 0x66, 0x28, 0x6f, - 0x0b, 0xa1, 0x5b, 0x03, 0xd6, 0xaf, 0x36, 0xd0, 0xfb, 0xfd, 0x07, 0x1d, 0xdd, 0x1b, 0xe8, 0x24, - 0xe8, 0xe1, 0x3e, 0xd1, 0xc1, 0x24, 0xd3, 0xc1, 0xec, 0xd9, 0xbf, 0xd2, 0xb0, 0xdf, 0x17, 0x72, - 0xb7, 0xc2, 0xa8, 0x03, 0xdd, 0xea, 0xcb, 0xd2, 0x59, 0x61, 0xe1, 0xe4, 0xde, 0x84, 0xbc, 0xe9, - 0xd6, 0x2a, 0xfa, 0x1a, 0x9e, 0x34, 0x7f, 0x87, 0xb5, 0x60, 0x3a, 0x2f, 0xa2, 0xa3, 0x59, 0x6a, - 0x0c, 0x9a, 0x07, 0xae, 0x96, 0xee, 0xa0, 0x29, 0x5d, 0x31, 0xfa, 0x1c, 0xa0, 0x9a, 0x93, 0x73, - 0x17, 0x05, 0xf7, 0x38, 0x4b, 0x8d, 0x5e, 0x75, 0xcc, 0x6a, 0xe9, 0xf6, 0x2a, 0xc1, 0x8a, 0x59, - 0xaf, 0xa0, 0x53, 0xba, 0xa5, 0x7d, 0xe8, 0x7e, 0x8c, 0xb6, 0x91, 0xbc, 0x8e, 0x86, 0x2d, 0xda, - 0x83, 0xa3, 0x77, 0xd7, 0x11, 0x57, 0x43, 0x42, 0x01, 0x3a, 0x73, 0x1f, 0xc5, 0x15, 0x1f, 0x6a, - 0xb9, 0x66, 0xb1, 0x93, 0xfe, 0x96, 0xb3, 0x61, 0x7b, 0x31, 0xbd, 0xc9, 0x26, 0xe4, 0x7b, 0x36, - 0x21, 0xb7, 0xd9, 0x84, 0x7c, 0xfd, 0x39, 0x69, 0x7d, 0x7a, 0x5a, 0x5e, 0x0b, 0xb9, 0x7f, 0xe9, - 0xf8, 0x52, 0x71, 0xa7, 0xbc, 0xe0, 0xa6, 0x53, 0x44, 0xfd, 0xf2, 0x6f, 0x00, 0x00, 0x00, 0xff, - 0xff, 0x62, 0x60, 0x6d, 0x95, 0xec, 0x03, 0x00, 0x00, +var fileDescriptor_conversation_51d7f1b4387b1405 = []byte{ + // 502 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x93, 0x31, 0x6f, 0xd3, 0x40, + 0x14, 0xc7, 0x6b, 0x87, 0x26, 0xe4, 0xa5, 0x84, 0xe8, 0x94, 0x22, 0x37, 0x43, 0x6c, 0x79, 0x21, + 0x03, 0xb2, 0x51, 0x98, 0x28, 0x42, 0x28, 0x69, 0x96, 0x0c, 0x08, 0xc9, 0xc0, 0xc2, 0x12, 0x5d, + 0x7c, 0x57, 0xf7, 0x94, 0xd8, 0x67, 0x2e, 0x2f, 0xad, 0xf2, 0x2d, 0x18, 0xf9, 0x48, 0x1d, 0xf9, + 0x04, 0xa1, 0x32, 0x0b, 0x23, 0xf0, 0x09, 0x90, 0xcf, 0xb6, 0x6a, 0xa9, 0x03, 0xea, 0xc8, 0xe4, + 0xbb, 0x77, 0xff, 0xdf, 0xff, 0xfe, 0xef, 0xd9, 0x86, 0x13, 0x9e, 0xa0, 0xc0, 0x9d, 0x1f, 0xca, + 0xe4, 0x92, 0xab, 0x0d, 0x45, 0x21, 0x13, 0x2f, 0x55, 0x12, 0x25, 0x39, 0x5a, 0x72, 0x85, 0x3b, + 0xaf, 0x10, 0x0c, 0x5c, 0x9a, 0x0a, 0x5f, 0x1f, 0x2c, 0xb7, 0xe7, 0x7e, 0xa4, 0x68, 0x7a, 0xf1, + 0x79, 0x5d, 0x3d, 0x0b, 0x62, 0xd0, 0x8f, 0x64, 0x24, 0xf5, 0xd2, 0xcf, 0x57, 0x65, 0xd5, 0x8e, + 0xa4, 0x8c, 0xd6, 0xfc, 0x16, 0x46, 0x11, 0xf3, 0x0d, 0xd2, 0x38, 0xad, 0xb0, 0xdb, 0x0c, 0x48, + 0x43, 0x2c, 0xaa, 0xee, 0x6f, 0x13, 0x8e, 0xce, 0x6a, 0xa9, 0xc8, 0x73, 0x30, 0x05, 0xb3, 0x0c, + 0xc7, 0x18, 0xb5, 0xa7, 0xce, 0xcd, 0xaf, 0x13, 0x23, 0xdb, 0xdb, 0xe6, 0x7c, 0xf6, 0x67, 0x6f, + 0x93, 0x48, 0xaa, 0xf8, 0xd4, 0x4d, 0x95, 0x88, 0xa9, 0xda, 0x2d, 0x56, 0x7c, 0xe7, 0x06, 0xa6, + 0x60, 0xe4, 0x0c, 0x20, 0x54, 0x9c, 0x22, 0x67, 0x0b, 0x8a, 0x96, 0xe9, 0x18, 0xa3, 0xce, 0x78, + 0xe0, 0x15, 0x71, 0xbc, 0x2a, 0x8e, 0xf7, 0xa1, 0x8a, 0x33, 0x7d, 0x78, 0xbd, 0xb7, 0x0f, 0xbe, + 0x7c, 0xb7, 0x8d, 0xa0, 0x5d, 0x72, 0x13, 0xcc, 0x4d, 0xb6, 0x29, 0xab, 0x4c, 0x1a, 0xf7, 0x31, + 0x29, 0xb9, 0x09, 0x92, 0xd7, 0xd0, 0x52, 0x9c, 0x6a, 0x87, 0x07, 0xf7, 0x70, 0x68, 0xe6, 0xd0, + 0x04, 0x49, 0x1f, 0x0e, 0x51, 0xe0, 0x9a, 0x5b, 0xfd, 0xbc, 0xfb, 0xa0, 0xd8, 0xe8, 0xaa, 0x4c, + 0x45, 0x68, 0x1d, 0x97, 0xd5, 0x7c, 0x43, 0x4e, 0xa1, 0x15, 0xf3, 0x78, 0xc9, 0xd5, 0xc6, 0x62, + 0x4e, 0x63, 0xd4, 0x19, 0x3b, 0x5e, 0xfd, 0x45, 0x7a, 0xf5, 0x99, 0xbe, 0xd5, 0xc2, 0xa0, 0x02, + 0xdc, 0x9f, 0x0d, 0x20, 0x77, 0xcf, 0xff, 0xeb, 0xc9, 0xbf, 0x81, 0xe6, 0x06, 0x29, 0x6e, 0x37, + 0x16, 0x38, 0xc6, 0xa8, 0x3b, 0x7e, 0xfa, 0xaf, 0x69, 0x78, 0xef, 0xb5, 0x3c, 0x28, 0x31, 0xe2, + 0x43, 0xab, 0xfc, 0x30, 0x2d, 0xa6, 0x23, 0x1c, 0xdf, 0x71, 0xc8, 0x0f, 0x83, 0x4a, 0x45, 0x5e, + 0xc1, 0xe3, 0xfa, 0xdf, 0xb4, 0x10, 0xcc, 0xe2, 0x7a, 0x74, 0x24, 0xdb, 0xdb, 0xdd, 0xfa, 0x85, + 0xf3, 0x59, 0xd0, 0xad, 0x4b, 0xe7, 0x8c, 0x3c, 0x03, 0x28, 0x7d, 0x72, 0xee, 0x5c, 0x73, 0x8f, + 0xb2, 0xbd, 0xdd, 0x2e, 0xaf, 0x99, 0xcf, 0x82, 0x76, 0x29, 0x98, 0x33, 0xf7, 0x25, 0x34, 0x8b, + 0xb4, 0xa4, 0x03, 0xad, 0x8f, 0xc9, 0x2a, 0x91, 0x57, 0x49, 0xef, 0x80, 0xb4, 0xe1, 0xf0, 0xdd, + 0x55, 0xc2, 0x55, 0xcf, 0x20, 0x00, 0xcd, 0x49, 0x88, 0xe2, 0x92, 0xf7, 0xcc, 0x5c, 0x33, 0x5d, + 0xcb, 0x70, 0xc5, 0x59, 0xaf, 0x31, 0x1d, 0x5d, 0x67, 0x43, 0xe3, 0x5b, 0x36, 0x34, 0x6e, 0xb2, + 0xa1, 0xf1, 0xf5, 0xc7, 0xf0, 0xe0, 0xd3, 0x93, 0xa2, 0x2d, 0xe4, 0xe1, 0x85, 0x1f, 0x4a, 0xc5, + 0xfd, 0xa2, 0xc1, 0x65, 0x53, 0x8f, 0xfa, 0xc5, 0xdf, 0x00, 0x00, 0x00, 0xff, 0xff, 0xd9, 0x9e, + 0xe2, 0xe2, 0x2b, 0x04, 0x00, 0x00, } diff --git a/core/entity/conversation.proto b/core/entity/conversation.proto index c429503476..1775501af0 100644 --- a/core/entity/conversation.proto +++ b/core/entity/conversation.proto @@ -17,6 +17,7 @@ message Conversation { string id = 1 [(gql.graphql_id) = true, (gogoproto.moretags) = "gorm:\"primary_key\"", (gogoproto.customname) = "ID"]; 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]; // // metadata diff --git a/core/go.mod b/core/go.mod index bb98865326..4c2463e323 100644 --- a/core/go.mod +++ b/core/go.mod @@ -32,7 +32,7 @@ require ( github.com/go-stack/stack v1.8.0 // indirect github.com/gobuffalo/packr/v2 v2.0.0-rc.12 github.com/gofrs/uuid v3.1.0+incompatible - github.com/gogo/protobuf v1.1.1 + github.com/gogo/protobuf v1.2.0 github.com/golang/protobuf v1.2.0 github.com/google/go-cmp v0.2.0 // indirect github.com/google/uuid v1.0.0 // indirect @@ -72,25 +72,25 @@ require ( github.com/libp2p/go-libp2p-circuit v2.2.8+incompatible github.com/libp2p/go-libp2p-crypto v2.0.1+incompatible github.com/libp2p/go-libp2p-host v3.0.13+incompatible - github.com/libp2p/go-libp2p-interface-connmgr v0.0.19 + github.com/libp2p/go-libp2p-interface-connmgr v0.0.21 github.com/libp2p/go-libp2p-interface-pnet v3.0.0+incompatible - github.com/libp2p/go-libp2p-kad-dht v4.4.8+incompatible + github.com/libp2p/go-libp2p-kad-dht v4.4.12+incompatible github.com/libp2p/go-libp2p-kbucket v2.2.11+incompatible // indirect github.com/libp2p/go-libp2p-loggables v1.1.22 // indirect github.com/libp2p/go-libp2p-metrics v2.1.6+incompatible github.com/libp2p/go-libp2p-nat v0.8.7 // indirect github.com/libp2p/go-libp2p-net v3.0.13+incompatible github.com/libp2p/go-libp2p-netutil v0.4.11 // indirect - github.com/libp2p/go-libp2p-peer v2.3.8+incompatible + github.com/libp2p/go-libp2p-peer v2.4.0+incompatible github.com/libp2p/go-libp2p-peerstore v2.0.4+incompatible github.com/libp2p/go-libp2p-pnet v3.0.4+incompatible github.com/libp2p/go-libp2p-protocol v1.0.0 github.com/libp2p/go-libp2p-pubsub v0.10.2 // indirect github.com/libp2p/go-libp2p-record v4.1.7+incompatible // indirect - github.com/libp2p/go-libp2p-routing v2.6.5+incompatible // indirect + github.com/libp2p/go-libp2p-routing v2.7.1+incompatible // indirect github.com/libp2p/go-libp2p-secio v2.0.15+incompatible // indirect github.com/libp2p/go-libp2p-swarm v3.0.19+incompatible // indirect - github.com/libp2p/go-libp2p-transport v3.0.13+incompatible + github.com/libp2p/go-libp2p-transport v3.0.15+incompatible github.com/libp2p/go-libp2p-transport-upgrader v0.1.14 // indirect github.com/libp2p/go-maddr-filter v1.1.9 // indirect github.com/libp2p/go-mplex v0.2.30 // indirect @@ -123,7 +123,7 @@ require ( github.com/oxtoacart/bpool v0.0.0-20150712133111-4e1c5567d7c2 // indirect github.com/pkg/errors v0.8.0 github.com/rs/cors v1.6.0 - github.com/satori/go.uuid v1.2.0 // indirect + github.com/satori/go.uuid v1.2.0 github.com/sergi/go-diff v1.0.0 // indirect github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d // indirect github.com/smartystreets/goconvey v0.0.0-20180222194500-ef6db91d284a @@ -135,7 +135,7 @@ require ( github.com/uber-go/atomic v1.3.2 // indirect github.com/uber/jaeger-client-go v2.15.0+incompatible github.com/uber/jaeger-lib v1.5.0 // indirect - github.com/vektah/gqlparser v0.0.0-20181002002754-f119686bf1d4 // indirect + github.com/vektah/gqlparser v1.0.0 github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc // indirect github.com/whyrusleeping/cbor v0.0.0-20171005072247-63513f603b11 // indirect github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 // indirect diff --git a/core/go.sum b/core/go.sum index f037c61c1b..79c5c620ae 100644 --- a/core/go.sum +++ b/core/go.sum @@ -233,6 +233,8 @@ github.com/gofrs/uuid v3.1.0+incompatible h1:q2rtkjaKT4YEr6E1kamy0Ha4RtepWlQBedy github.com/gofrs/uuid v3.1.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.1.1 h1:72R+M5VuhED/KujmZVcIquuo8mBgX4oVda//DQb3PXo= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.0 h1:xU6/SpYbvkNYiptHJYEDRseDLvYE7wSqhYYNy0QSUzI= +github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= @@ -356,10 +358,14 @@ github.com/libp2p/go-libp2p-host v3.0.13+incompatible h1:wWWH5jtgyR6vBABU7OMkL9F github.com/libp2p/go-libp2p-host v3.0.13+incompatible/go.mod h1:iAthoepYpyqzb89f4RmqzF9+ebsWPFBTvSedSlcWupg= github.com/libp2p/go-libp2p-interface-connmgr v0.0.19 h1:s454gG+X/CDfSw6PMKCPizdIm0GEwyhrk59Y+8KA320= github.com/libp2p/go-libp2p-interface-connmgr v0.0.19/go.mod h1:2LbTwxMveREcmkOWo/s6MM7xDvSZbW8J8kYDF4Mj648= +github.com/libp2p/go-libp2p-interface-connmgr v0.0.21 h1:XJtqDLi860LtusR6mY2PCPGeYXmFjm7gXb+ksqwnCpI= +github.com/libp2p/go-libp2p-interface-connmgr v0.0.21/go.mod h1:2LbTwxMveREcmkOWo/s6MM7xDvSZbW8J8kYDF4Mj648= github.com/libp2p/go-libp2p-interface-pnet v3.0.0+incompatible h1:MNYpwR4opxOJGkDdlV4Vypd7aM6mlt76fad4m4KLk4k= github.com/libp2p/go-libp2p-interface-pnet v3.0.0+incompatible/go.mod h1:el9jHpQAXK5dnTpKA4yfCNBZXvrzdOU75zz+C6ryp3k= github.com/libp2p/go-libp2p-kad-dht v4.4.8+incompatible h1:ki4NmxpmtBh3Xrme7FE2lTPYAos0CW85zYYCSxIZStI= github.com/libp2p/go-libp2p-kad-dht v4.4.8+incompatible/go.mod h1:o7SLAgKvO96vfE0SrzjJfAdCbJjKRfRnbtyUIQg+rqg= +github.com/libp2p/go-libp2p-kad-dht v4.4.12+incompatible h1:l5SmsvVxRTFO2+3Wg/91b5ElAQ1fZD7Z40KsWOXgZq8= +github.com/libp2p/go-libp2p-kad-dht v4.4.12+incompatible/go.mod h1:o7SLAgKvO96vfE0SrzjJfAdCbJjKRfRnbtyUIQg+rqg= github.com/libp2p/go-libp2p-kbucket v2.2.11+incompatible h1:G2tHiXSVhQ9n404QR/L2qoikt+WVYzfkukHqQKXd13c= github.com/libp2p/go-libp2p-kbucket v2.2.11+incompatible/go.mod h1:MTtm31eal94QTxVOWYTDZ6G1YOJRN2G3ESQHbaPytLk= github.com/libp2p/go-libp2p-loggables v1.1.22 h1:n25P9uYpSCmZUE5brUZyjoyB9QjyFb4M60A/PM5wr3k= @@ -374,6 +380,8 @@ github.com/libp2p/go-libp2p-netutil v0.4.11 h1:eLPFmbMevDPTVee0MPd29Syc3sncvDjDu github.com/libp2p/go-libp2p-netutil v0.4.11/go.mod h1:lpxjq1x/eUtPYAZAtnC7dKWjQeTuYIYz2ZIPNDDBj3g= github.com/libp2p/go-libp2p-peer v2.3.8+incompatible h1:ZMYXJdcX/38UBDjrl5BEYRGRgDkc+r+oMSfysyPM/MQ= github.com/libp2p/go-libp2p-peer v2.3.8+incompatible/go.mod h1:fS2eFKRO1IomwBAf+SuE8P1XOT/AAiqSgVPNIFA7Jc0= +github.com/libp2p/go-libp2p-peer v2.4.0+incompatible h1:1THIuO/h7GuITklYS7RgGCyoVl8aP9XH4NcokcdhDZc= +github.com/libp2p/go-libp2p-peer v2.4.0+incompatible/go.mod h1:fS2eFKRO1IomwBAf+SuE8P1XOT/AAiqSgVPNIFA7Jc0= github.com/libp2p/go-libp2p-peerstore v2.0.4+incompatible h1:4dOjYQ/y38mBw9m9/pcAGSv+5PxK4dS37cEOSsaF7zo= github.com/libp2p/go-libp2p-peerstore v2.0.4+incompatible/go.mod h1:lLfgn0N3z2t+ER57a88K7NTZjMO27ez5TyWSURd428E= github.com/libp2p/go-libp2p-pnet v3.0.4+incompatible h1:+jY7/4M41k86g0E/ctEmabLdQeXGrwl+8ZxDK16Nt88= @@ -386,12 +394,16 @@ github.com/libp2p/go-libp2p-record v4.1.7+incompatible h1:SDxar7iuh4z03b85lr8tVM github.com/libp2p/go-libp2p-record v4.1.7+incompatible/go.mod h1:fsxr7H89UzzL4pG23Aq2n/5aNAXxdGEbyBVepo8oXy8= github.com/libp2p/go-libp2p-routing v2.6.5+incompatible h1:wYohT0oyssCQcGjNHFuZhRZMbMAVt5KtsoaHIvgbo0U= github.com/libp2p/go-libp2p-routing v2.6.5+incompatible/go.mod h1:Alff8O712wWiftX462zvknNmi5RmXtLq/gATcxJ/Hq8= +github.com/libp2p/go-libp2p-routing v2.7.1+incompatible h1:uS0k70z1Bmu6LKTofR6FhbNMBzZsS5uwHzLD3LjT3no= +github.com/libp2p/go-libp2p-routing v2.7.1+incompatible/go.mod h1:Alff8O712wWiftX462zvknNmi5RmXtLq/gATcxJ/Hq8= github.com/libp2p/go-libp2p-secio v2.0.15+incompatible h1:WqyV9tDkHUaWt0P1UErXMw8aLyjDgPsnXch7BeIIwfI= github.com/libp2p/go-libp2p-secio v2.0.15+incompatible/go.mod h1:U7wBlYK2sZbUiTaGe6xJd/fyNq40gwn+jBk/iEUbUrA= github.com/libp2p/go-libp2p-swarm v3.0.19+incompatible h1:GbyyHSORop2m9AGGQsdAVtKFyAplH2cjxFToFpoFDhM= github.com/libp2p/go-libp2p-swarm v3.0.19+incompatible/go.mod h1:NHa7cA4/y8OKFw3BHQjLL9pwPDFXkgECO/k+2gqSFuk= github.com/libp2p/go-libp2p-transport v3.0.13+incompatible h1:mSMrXQklxnAu4qOJQtYB4AUAujPgpmvDkISp+13s2SY= github.com/libp2p/go-libp2p-transport v3.0.13+incompatible/go.mod h1:lcwgOszllbhvQXul37Kv5YbSYXPoUhRB2Z+Nr3jaBmo= +github.com/libp2p/go-libp2p-transport v3.0.15+incompatible h1:48KfTznuB0vEPcGN+exe3Au92Q4HvcZS3YTVMZbIQhs= +github.com/libp2p/go-libp2p-transport v3.0.15+incompatible/go.mod h1:lcwgOszllbhvQXul37Kv5YbSYXPoUhRB2Z+Nr3jaBmo= github.com/libp2p/go-libp2p-transport-upgrader v0.1.14 h1:2VzOHRAuaT/rOBmggl0XmV0w17m0Vvt+4NMf/bvuQOU= github.com/libp2p/go-libp2p-transport-upgrader v0.1.14/go.mod h1:5r+arPlxwtCEF1aVi/fTQF/ZWGSPHLxBov1DlXDevDA= github.com/libp2p/go-maddr-filter v1.1.9 h1:832yvrYARYYldUTIUR069BpDICwg8kgjebbfTrZpc0M= @@ -555,6 +567,8 @@ github.com/unrolled/secure v0.0.0-20180918153822-f340ee86eb8b/go.mod h1:mnPT77IA github.com/unrolled/secure v0.0.0-20181005190816-ff9db2ff917f/go.mod h1:mnPT77IAdsi/kV7+Es7y+pXALeV3h7G6dQF6mNYjcLA= github.com/vektah/gqlparser v0.0.0-20181002002754-f119686bf1d4 h1:HOJJtIE3gsOqjNxZF8LZ0pVMC7VGJgZlTSUbMCoQvTA= github.com/vektah/gqlparser v0.0.0-20181002002754-f119686bf1d4/go.mod h1:K4QdSSpS2XiHHwzb18kWh3iBljB8rLC8okGXsnQy3Nc= +github.com/vektah/gqlparser v1.0.0 h1:sa/YH/EczjNUFh/ww8ZOsEt/Z7bUMVHI/PH8U0a+taM= +github.com/vektah/gqlparser v1.0.0/go.mod h1:K4QdSSpS2XiHHwzb18kWh3iBljB8rLC8okGXsnQy3Nc= github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc h1:BCPnHtcboadS0DvysUuJXZ4lWVv5Bh5i7+tbIyi+ck4= github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc/go.mod h1:r45hJU7yEoA81k6MWNhpMj/kms0n14dkzkxYHoB96UM= github.com/whyrusleeping/cbor v0.0.0-20171005072247-63513f603b11 h1:5HZfQkwe0mIfyDmc1Em5GqlNRzcdtlv4HTNmdpt7XH0= diff --git a/core/node/event_handlers.go b/core/node/event_handlers.go index 9317443743..5758861dab 100644 --- a/core/node/event_handlers.go +++ b/core/node/event_handlers.go @@ -137,7 +137,8 @@ func (n *Node) handleConversationNewMessage(ctx context.Context, input *p2p.Even return err } - // nothing to do + // say that conversation has not been read + n.sql.Save(&entity.Conversation{ID: input.ConversationID, ReadAt: time.Time{}}) return nil } diff --git a/core/node/nodeapi.go b/core/node/nodeapi.go index f74363c27e..c49b23fdc1 100644 --- a/core/node/nodeapi.go +++ b/core/node/nodeapi.go @@ -4,16 +4,16 @@ import ( "context" "time" - "berty.tech/core/pkg/errorcodes" - - "github.com/jinzhu/gorm" - "berty.tech/core/api/node" "berty.tech/core/api/p2p" + gql "berty.tech/core/api/protobuf/graphql" "berty.tech/core/entity" + "berty.tech/core/pkg/errorcodes" "berty.tech/core/pkg/tracing" bsql "berty.tech/core/sql" + "github.com/jinzhu/gorm" "github.com/opentracing/opentracing-go" + opentracing "github.com/opentracing/opentracing-go" "github.com/pkg/errors" "google.golang.org/grpc" ) @@ -70,33 +70,59 @@ func (n *Node) EventList(input *node.EventListInput, stream node.Service_EventLi return nil } -func (n *Node) EventSeen(ctx context.Context, input *node.EventIDInput) (*p2p.Event, error) { +func (n *Node) EventSeen(ctx context.Context, input *gql.Node) (*p2p.Event, error) { var span opentracing.Span span, ctx = tracing.EnterFunc(ctx, input) defer span.Finish() n.handleMutex(ctx)() event := &p2p.Event{} - count := 0 sql := n.sql(ctx) if err := sql. Model(&p2p.Event{}). - Where(&p2p.Event{ID: input.EventID}). - Count(&count). + Where(&p2p.Event{ID: input.ID}). UpdateColumn("seen_at", time.Now().UTC()). First(event). Error; err != nil { return nil, errorcodes.ErrDbUpdate.Wrap(err) } - if count == 0 { - return nil, errorcodes.ErrDbNothingFound.New() + // mark conversation as read + if event.ConversationID != "" { + _, err := n.ConversationRead(ctx, &gql.Node{ID: event.ConversationID}) + if err != nil { + return nil, err + } } return event, nil } +func (n *Node) ConversationRead(ctx context.Context, input *gql.Node) (*entity.Conversation, error) { + // get conversation + conversation := &entity.Conversation{ID: input.ID} + if err := n.sql.Model(conversation).Where(conversation).First(conversation).Error; err != nil { + return nil, err + } + + // check if last message has been read + event := &p2p.Event{ConversationID: conversation.ID} + count := 0 + n.sql.Model(event).Where(event).Order("created_at").Count(&count).Last(event) + if count > 0 && event.SeenAt == nil { + return conversation, nil + } + + // set conversation as read + conversation.ReadAt = time.Now().UTC() + if err := n.sql.Save(conversation).Error; err != nil { + return nil, errors.Wrap(err, "cannot update conversation") + } + + return conversation, nil +} + // GetEvent implements berty.node.GetEvent func (n *Node) GetEvent(ctx context.Context, input *p2p.Event) (*p2p.Event, error) { var span opentracing.Span