~aleteoryx/muditaos

e13ed40fa4c463db69655531c8a9d44b43e299e2 — Lukasz Mastalerz 2 years ago 015d8ea
[CP-1624] Adding numberID as a field to contact and message response

Changing the way Center is recognizing the threads in the message
window by introducing the numberID
M doc/os_api/endpoints/pure/contacts_endpoint.md => doc/os_api/endpoints/pure/contacts_endpoint.md +206 -164
@@ 1,103 1,120 @@
Contacts endpoint (7)
=============================

* [Parameters explanation](#parameters-explanation)
* [Pagination](#pagination)
* [Usage examples](#usage-examples)
  * [Get contacts count](#get-contacts-count)
  * [Get contacts using offset and limit](#get-contacts-using-offset-and-limit)
  * [Get a contact by ID](#get-a-contact-by-id)
  * [Add a new contact](#add-a-new-contact)
  * [Update a contact](#update-a-contact)
  * [Delete a contact](#delete-a-contact)

    * [Get contacts count](#get-contacts-count)
    * [Get contacts using offset and limit](#get-contacts-using-offset-and-limit)
    * [Get a contact by ID](#get-a-contact-by-id)
    * [Add a new contact](#add-a-new-contact)
    * [Update a contact](#update-a-contact)
    * [Delete a contact](#delete-a-contact)

## Parameters explanation

[Common parameters explanation](../../protocol_description/common_parameters_explanation.md)

## Pagination 
## Pagination

[Pagination](../../protocol_description/pagination.md)

## Usage examples

### Get contacts count

**Note: For development/testing purposes only.**
**Request Payload Structure**
```

```json
{
   "endpoint":7,
   "method":1,
   "uuid":1,
   "body":{
      "count":true
   }
  "endpoint": 7,
  "method": 1,
  "uuid": 1,
  "body": {
    "count": true
  }
}
```

**Response Payload Structure**
```

```json
{
   "body":{
      "count":76
   },
   "endpoint":7,
   "status":200,
   "uuid":1
  "body": {
    "count": 76
  },
  "endpoint": 7,
  "status": 200,
  "uuid": 1
}
```

### Get contacts using offset and limit

See: [Pagination](../../protocol_description/pagination.md)
**Request Payload Structure**
```

```json
{
   "endpoint":7,
   "method":1,
   "uuid":123,
   "body":{
      "offset":0,
      "limit":2
   }
  "endpoint": 7,
  "method": 1,
  "uuid": 123,
  "body": {
    "offset": 0,
    "limit": 2
  }
}
```

**Response Payload Structure**
```

```json
{
   "body":{
      "entries":[
         {
            "address":"Czeczota 6, 02-600 Warsaw, Poland",
            "altName":"Abraham",
            "email":"Abraham@example.com",
            "blocked":false,
            "favourite":true,
            "ice":true,
            "id":1,
            "numbers":[
               "123456789"
            ],
            "speedDial":"",
            "priName":"Olivia",
            "note":""
         },
         {
            "address":"Czeczota 6, 02-600 Warsaw, Poland",
            "altName":"Alsop",
            "email":"Alsop@example.com",
            "blocked":false,
            "favourite":true,
            "ice":true,
            "id":3,
            "numbers":[
               "123456789"
            ],
            "speedDial":"7",
            "priName":"Charles",
            "note":""
         }
      ],
      "totalCount":76
   },
   "endpoint":7,
   "status":200,
   "uuid":123
  "body": {
    "entries": [
      {
        "address": "Czeczota 6, 02-600 Warsaw, Poland",
        "altName": "Abraham",
        "email": "Abraham@example.com",
        "blocked": false,
        "favourite": true,
        "ice": true,
        "id": 1,
        "numbers": [
          "123456789"
        ],
        "numbersIDs": [
          "1"
        ],
        "speedDial": "",
        "priName": "Olivia",
        "note": ""
      },
      {
        "address": "Czeczota 6, 02-600 Warsaw, Poland",
        "altName": "Alsop",
        "email": "Alsop@example.com",
        "blocked": false,
        "favourite": true,
        "ice": true,
        "id": 3,
        "numbers": [
          "123456789"
        ],
        "numbersIDs": [
          "1"
        ],
        "speedDial": "7",
        "priName": "Charles",
        "note": ""
      }
    ],
    "totalCount": 76
  },
  "endpoint": 7,
  "status": 200,
  "uuid": 123
}
```



@@ 111,155 128,180 @@ Parameters:
- *ice* - true if contact is on in case of emergency list
- *id* - contact id
- *numbers* - list of contact numbers
- *numbersIDs* - list of numbers ids corresponded to *numbers*
- *speedDial* - speed dial number
- *priName* - primary name of contact
- *note* - note attached to contact

### Get a contact by ID

**Note: For development/testing purposes only.**
**Request Payload Structure**
```

```json
{
   "endpoint":7,
   "method":1,
   "uuid":1,
   "body":{
      "id":5
   }
  "endpoint": 7,
  "method": 1,
  "uuid": 1,
  "body": {
    "id": 5
  }
}
```

**Response Payload Structure**
```

```json
{
   "body":{
      "address":"Czeczota 6, 02-600 Warsaw, Poland",
      "altName":"Arnold",
      "email": "Arnold@example.com",
      "blocked":false,
      "favourite":false,
      "ice":true,
      "id":5,
      "numbers":[
         "123456789"
      ],
      "speedDial":"6",
      "priName":"Donna",
      "note":"likes oranges"
   },
   "endpoint":7,
   "status":200,
   "uuid":1
  "body": {
    "address": "Czeczota 6, 02-600 Warsaw, Poland",
    "altName": "Arnold",
    "email": "Arnold@example.com",
    "blocked": false,
    "favourite": false,
    "ice": true,
    "id": 5,
    "numbers": [
      "123456789"
    ],
    "numbersIDs": [
      "1"
    ],
    "speedDial": "6",
    "priName": "Donna",
    "note": "likes oranges"
  },
  "endpoint": 7,
  "status": 200,
  "uuid": 1
}
```

### Add a new contact

**Request Payload Structure**
```

```json
{
   "endpoint":7,
   "method":2,
   "uuid":123,
   "body":{
      "address":"Czeczota 6, 02-600 Warsaw, Poland",
      "altName":"Turk",
      "email":"Turk@example.com",
      "blocked":false,
      "favourite":true,
      "ice":false,
      "numbers":[
         "123456789"
      ],
      "speedDial":"",
      "priName":"Tolek",
      "note":"has a cat"
   }
  "endpoint": 7,
  "method": 2,
  "uuid": 123,
  "body": {
    "address": "Czeczota 6, 02-600 Warsaw, Poland",
    "altName": "Turk",
    "email": "Turk@example.com",
    "blocked": false,
    "favourite": true,
    "ice": false,
    "numbers": [
      "123456789"
    ],
    "speedDial": "",
    "priName": "Tolek",
    "note": "has a cat"
  }
}
```

**Response Payload Structure when contact is successfully added**
```
{

```json
{
   "body":{
      "id":77
   },
   "endpoint":7,
   "status":200,
   "uuid":123
  "body": {
    "id": 77
  },
  "endpoint": 7,
  "status": 200,
  "uuid": 123
}
```

Parameters:

- *id*  - id of newly created contact

**Response Payload Structure when contact is matched as a duplicate**
```

```json
{
   "body":{
      "id":76
   },
   "endpoint":7,
   "status":409,
   "uuid":123
  "body": {
    "id": 76
  },
  "endpoint": 7,
  "status": 409,
  "uuid": 123
}
```

Parameters:

- *id*  - id of duplicated contact

### Update a contact

**Request Payload Structure**
```

```json
{
   "endpoint":7,
   "method":3,
   "uuid":123,
   "body":{
      "id":77,
      "address":"Czeczota 6, 02-600 Warsaw, Poland",
      "altName":"Turk",
      "email":"Turk@example.com",
      "blocked":false,
      "favourite":true,
      "ice":false,
      "numbers":[
         "123456789"
      ],
      "speedDial":"",
      "priName":"Tolek",
      "note":"has a cat"
   }
  "endpoint": 7,
  "method": 3,
  "uuid": 123,
  "body": {
    "id": 77,
    "address": "Czeczota 6, 02-600 Warsaw, Poland",
    "altName": "Turk",
    "email": "Turk@example.com",
    "blocked": false,
    "favourite": true,
    "ice": false,
    "numbers": [
      "123456789"
    ],
    "speedDial": "",
    "priName": "Tolek",
    "note": "has a cat"
  }
}
```

**Response Payload Structure when contact is successfully updated**
```

```json
{
   "endpoint":7,
   "status":204,
   "uuid":123
  "endpoint": 7,
  "status": 204,
  "uuid": 123
}
```
Warning: 

Warning:
In the current implementation, there is no duplicate detection while updating contact.
Example:
We have contact A with number 123 and contact B with number 456.
Contact A is updated with a new number - 456. Number 456 is silently unattached from contact B and assigned to contact A. Finally, we have contact A with number 456 and contact B with no number.
Contact A is updated with a new number - 456. Number 456 is silently unattached from contact B and assigned to contact
A. Finally, we have contact A with number 456 and contact B with no number.

### Delete a contact

**Request Payload Structure**
```

```json
{
   "endpoint":7,
   "method":4,
   "uuid":1,
   "body":{
      "id":77
   }
  "endpoint": 7,
  "method": 4,
  "uuid": 1,
  "body": {
    "id": 77
  }
}
```

**Response Payload Structure**
```

```json
{
   "endpoint":7,
   "status":204,
   "uuid":1
  "endpoint": 7,
  "status": 204,
  "uuid": 1
}
```
\ No newline at end of file

A doc/os_api/endpoints/pure/messages_endpoint.md => doc/os_api/endpoints/pure/messages_endpoint.md +773 -0
@@ 0,0 1,773 @@
Messages endpoint (8)
=============================

* [Parameters explanation](#parameters-explanation)
* [Pagination](#pagination)
* [Usage examples](#usage-examples)
    * [Threads](#threads)
        * [Get threads using offset and limit](#get-threads-using-offset-and-limit)
        * [DEPRECATED Get a thread by ID](#deprecated-get-a-thread-by-id)
        * [Set a thread as read / unread](#set-a-thread-as-read--unread)
        * [Delete a thread](#delete-a-thread)
    * [Messages](#messages)
        * [Get messages count](#get-messages-count)
        * [Get messages using offset and limit](#get-messages-using-offset-and-limit)
        * [Get a message by ID](#get-a-message-by-id)
        * [Get messages by thread ID](#get-messages-by-thread-id)
        * [Add a new message](#add-a-new-message)
        * [Update draft message](#update-draft-message)
        * [Delete a message by ID](#delete-a-message-by-ID)
    * [Templates](#templates)
        * [Get a templates count](#get-a-templates-count)
        * [Get templates using offset and limit](#get-templates-using-offset-and-limit)
        * [Get a message template by ID](#get-a-message-template-by-id)
        * [Change a message template body](#change-a-message-template-body)
        * [Change a message template order](#change-a-message-template-order)
        * [Add a message template](#add-a-message-template)
        * [Delete a message template by id](#delete-a-message-template-by-id)

## Parameters explanation

[Common parameters explanation](../../protocol_description/common_parameters_explanation.md)

## Pagination

[Pagination](../../protocol_description/pagination.md)

## Usage examples

## Threads

### Get threads using offset and limit

See: [Pagination](../../protocol_description/pagination.md)
**Request Payload Structure**

```json
{
  "endpoint": 8,
  "method": 1,
  "uuid": 123,
  "body": {
    "category": "thread",
    "offset": 0,
    "limit": 3
  }
}
```

**Response Payload Structure**

```json
{
  "body": {
    "entries": [
      {
        "isUnread": true,
        "lastUpdatedAt": 1574335694,
        "messageCount": 6,
        "messageSnippet": "Wiadomo<0xc5><0x9b><0xc4><0x87> testowa.",
        "messageType": 1,
        "number": "123456789",
        "numberID": "1",
        "threadID": 1
      },
      {
        "isUnread": true,
        "lastUpdatedAt": 5,
        "messageCount": 1,
        "messageSnippet": "Lorem ipsum dolor sit amet, consectetur adipiscing",
        "messageType": 16,
        "number": "123456789",
        "numberID": "1",
        "threadID": 5
      },
      {
        "isUnread": false,
        "lastUpdatedAt": 5,
        "messageCount": 1,
        "messageSnippet": "cos tam",
        "messageType": 8,
        "number": "123456789",
        "numberID": "1",
        "threadID": 6
      }
    ],
    "nextPage": {
      "limit": 0,
      "offset": 0
    },
    "totalCount": 3
  },
  "endpoint": 8,
  "status": 200,
  "uuid": 123
}
```

Parameters:

- *totalCount*  - total number of threads on the PurePhone side
- *nextPage* - an offset and a limit that should be used to request the next page - in the example first current page
  consists of 3 elements. Because totalCount is 4 nextPage field is available.
- *threadID* - unique ID of the thread
- *lastUpdatedAt* - date of the last modification of the thread, epoch timestamp in seconds
- *messageCount* - number of messages in the thread
- *messageSnippet* - the first row of the last message in a given thread - text is encoded in UTF8 and has up to 45
  characters
- *isUnread* - true, if at least one unread message in the thread
- *messageType* - type of the last SMS in thread. (
  See: [Common parameters explanation](../../protocol_description/common_parameters_explanation.md))
- *number* - phone number associated with the given message thread
- *numberID* - id number corresponded to *number*

In the above example requested 7 elements cannot be met because *totalCount* is 4. Additionally, the response is split
into pages. The nextPage says how many elements (*limit*) and from what offset (*offset*) need to be requested to
reach
the *totalCount* or *limit* (whatever comes first). When field *nextPage* does not exist in the response it means that
the
request was completed within the current page.

### DEPRECATED Get a thread by ID

**Request Payload Structure**

```json
{
  "endpoint": 8,
  "method": 1,
  "uuid": 123,
  "body": {
    "category": "thread",
    "threadID": 8
  }
}
```

**Response Payload Structure**

```json
{
  "body": {
    "isUnread": false,
    "lastUpdatedAt": 1650656989,
    "messageCount": 1,
    "messageSnippet": "Hello",
    "messageType": 1,
    "threadID": 8
  },
  "endpoint": 8,
  "status": 200,
  "uuid": 123
}
```

### Set a thread as read / unread

**Request Payload Structure**

```json
{
  "endpoint": 8,
  "method": 3,
  "uuid": 123,
  "body": {
    "category": "thread",
    "threadID": 1,
    "isUnread": true
  }
}
```

Parameters:

- *isUnread* - set to true, if the thread should be marked as unread, or false if it should be marked as read

**Response Payload Structure**

```json
{
  "endpoint": 8,
  "status": 204,
  "uuid": 123
}
```

### Delete a thread

**Request Payload Structure**

```json
{
  "endpoint": 8,
  "method": 4,
  "uuid": 123,
  "body": {
    "category": "thread",
    "threadID": 1
  }
}
```

**Response Payload Structure**

```json
{
  "endpoint": 8,
  "status": 204,
  "uuid": 123
}
```

## Messages

### Get messages count

**Note: For development/testing purposes only.**
**Request Payload Structure**

```json
{
  "endpoint": 8,
  "method": 1,
  "uuid": 123,
  "body": {
    "category": "message",
    "count": true
  }
}
```

**Response Payload Structure**

```json
{
  "body": {
    "count": 13
  },
  "endpoint": 8,
  "status": 200,
  "uuid": 123
}
```

### Get messages using offset and limit

See: [Pagination](../../protocol_description/pagination.md)
**Request Payload Structure**

```json
{
  "endpoint": 8,
  "method": 1,
  "uuid": 123,
  "body": {
    "category": "message",
    "offset": 0,
    "limit": 13
  }
}
```

**Response Payload Structure**

```json
{
  "body": {
    "entries": [
      {
        "messageBody": "nieudane wysy<0xc5><0x82>anie :(",
        "messageID": 6,
        "messageType": 2,
        "createdAt": 1547492320,
        "threadID": 1,
        "number": "345678912"
      },
      {
        "messageBody": "Ci<0xc4><0x99><0xc5><0xbc>ko powiedzie<0xc4><0x87> o czym  ta wiadomo<0xc5><0x9b><0xc4><0x87> jest, ale jest do<0xc5><0x9b><0xc4><0x87> d<0xc5><0x82>uga.",
        "messageID": 7,
        "messageType": 2,
        "createdAt": 1547492320,
        "threadID": 2,
        "number": "456789123"
      },
      {
        "messageBody": "heh?",
        "messageID": 8,
        "messageType": 4,
        "createdAt": 1547492320,
        "threadID": 2,
        "number": "567891234"
      },
      {
        "messageBody": "abc",
        "messageID": 43,
        "messageType": 4,
        "createdAt": 1547492320,
        "threadID": 2,
        "number": "123456789"
      }
    ],
    "nextPage": {
      "limit": 4,
      "offset": 4
    },
    "totalCount": 13
  },
  "endpoint": 8,
  "status": 200,
  "uuid": 123
}
```

Parameters:

- *body*  - actual response from the endpoint
- *totalCount* - total number of messages stored in the PurePhone.
- *nextPage* - an offset and a limit that should be used to request for the next page
- *createdAt* - epoch timestamp in seconds, when message was created
- *threadID* - unique ID of the thread
- *number* - source number of the given message
- *messageID* - self-explanatory
- *messageBody* - text of the message
- *messageType* - SMS message type (
  See: [Common parameters explanation](../../protocol_description/common_parameters_explanation.md))

### Get a message by ID

**Note: For development/testing purposes only.**
**Request Payload Structure**

```json
{
  "endpoint": 8,
  "method": 1,
  "uuid": 123,
  "body": {
    "category": "message",
    "messageID": 8
  }
}
```

**Response Payload Structure**

```json
{
  "body": {
    "messageBody": "heh?",
    "messageID": 8,
    "messageType": 4,
    "createdAt": 1547492320,
    "threadID": 2,
    "number": "123456789"
  },
  "endpoint": 8,
  "status": 200,
  "uuid": 123
}
```

### Get messages by thread ID

**Request Payload Structure**

```json
{
  "endpoint": 8,
  "method": 1,
  "uuid": 123,
  "body": {
    "category": "message",
    "threadID": 1,
    "offset": 0,
    "limit": 6
  }
}
```

**Response Payload Structure**

```json
{
  "body": {
    "entries": [
      {
        "messageBody": "najstarsze odb fsjdklafjskldjf",
        "messageID": 1,
        "messageType": 4,
        "createdAt": 1547465101,
        "threadID": 1,
        "number": "123456789"
      },
      {
        "messageBody": "wys",
        "messageID": 2,
        "messageType": 8,
        "createdAt": 1547468701,
        "threadID": 1,
        "number": "123456789"
      },
      {
        "messageBody": "najnowsze odb i ca<0xc5><0x82>kiem 1 1 1 1 d<0xc5><0x82>ugie. d<0xc5><0x82>ugie d<0xc5><0x82>ugie d<0xc5><0x82>ugie, wcale nie kr<0xc3><0xb3>tkie.od nowej lini (\\n); i_teraz_zbyt_d<0xc5><0x82>uga_linia_<0xc5><0xbc>eby_si<0xc4><0x99>_zmie<0xc5><0x9b>ci<0xc4><0x87>",
        "messageID": 4,
        "messageType": 4,
        "createdAt": 1547472320,
        "threadID": 1,
        "number": "123456789"
      }
    ],
    "nextPage": {
      "limit": 2,
      "offset": 4
    },
    "totalCount": 6
  },
  "endpoint": 8,
  "status": 200,
  "uuid": 123
}
```

### Add a new message

**Request Payload Structure**

```json
{
  "endpoint": 8,
  "method": 2,
  "uuid": 123,
  "body": {
    "category": "message",
    "number": "+48236154528",
    "messageBody": "This is a new message",
    "messageType": 1
  }
}
```

Parameters:

- (optional) *messageType* - SMS message type (
  See: [Common parameters explanation](../../protocol_description/common_parameters_explanation.md)). Needed only if
  adding Draft type
  message (1).

**Success Response Payload Structure**

```json
{
  "body": {
    "messageBody": "This is a new message",
    "messageID": 8,
    "messageType": 4,
    "createdAt": 1547492320,
    "threadID": 2
  },
  "endpoint": 8,
  "status": 200,
  "uuid": 123
}
```

**Failure Response Payload Structure**
E.g. message body too long.

```json
{
  "endpoint": 8,
  "status": 400,
  "uuid": 123
}
```

### Update draft message

**Request Payload Structure**

```json
{
  "endpoint": 8,
  "method": 3,
  "uuid": 123,
  "body": {
    "category": "message",
    "messageBody": "This is a changed draft message",
    "messageID": 8,
    "messageType": 1
  }
}
```

**Response Payload Structure**

```json
{
  "endpoint": 8,
  "status": 204,
  "uuid": 123
}
```

### Delete a message by ID

**Request Payload Structure**

```json
{
  "endpoint": 8,
  "method": 4,
  "uuid": 123,
  "body": {
    "category": "message",
    "messageID": 2
  }
}
```

**Response Payload Structure**

```json
{
  "endpoint": 8,
  "status": 204,
  "uuid": 123
}
```

## Templates

### Get a templates count

**Note: For development/testing purposes only.**
**Request Payload Structure**

```json
{
  "endpoint": 8,
  "method": 1,
  "uuid": 123,
  "body": {
    "category": "template",
    "count": true
  }
}
```

**Response Payload Structure**

```json
{
  "body": {
    "count": 6
  },
  "endpoint": 8,
  "status": 200,
  "uuid": 123
}
```

### Get templates using offset and limit

**Request Payload Structure**

```json
{
  "endpoint": 8,
  "method": 1,
  "uuid": 123,
  "body": {
    "category": "template",
    "offset": 2,
    "limit": 3
  }
}
```

*Parameters were described in previous messages.*

**Response Payload Structure**

```json
{
  "body": {
    "entries": [
      {
        "lastUsedAt": 2,
        "order": 1,
        "templateBody": "I'll be there in 15 minutes",
        "templateID": 3
      },
      {
        "lastUsedAt": 1,
        "order": 2,
        "templateBody": "Some test tmplate number, which is too long to be displayed.",
        "templateID": 4
      },
      {
        "lastUsedAt": 0,
        "order": 3,
        "templateBody": "No.",
        "templateID": 5
      }
    ],
    "nextPage": {
      "limit": 1,
      "offset": 5
    },
    "totalCount": 6
  },
  "endpoint": 8,
  "status": 200,
  "uuid": 123
}
```

Parameters:

- *lastUsedAt* - epoch timestamp in seconds, when the template was last time used
- *templateID* - unique ID of the template
- *templateBody* - text of the template
- *order* - the order in which the template should be displayed

### Get a message template by ID

**Request Payload Structure**

```json
{
  "endpoint": 8,
  "method": 1,
  "uuid": 123,
  "body": {
    "category": "template",
    "templateID": 3
  }
}
```

**Response Payload Structure**

```json
{
  "body": {
    "lastUsedAt": 2,
    "order": 1,
    "templateBody": "I'll be there in 15 minutes",
    "templateID": 3
  },
  "endpoint": 8,
  "status": 200,
  "uuid": 123
}
```

### Change a message template body

**Request Payload Structure**

```json
{
  "endpoint": 8,
  "method": 3,
  "uuid": "123",
  "body": {
    "category": "template",
    "templateID": 2,
    "templateBody": "Changed template."
  }
}
```

**Response Payload Structure**

```json
{
  "endpoint": 8,
  "status": 204,
  "uuid": 123
}
```

### Change a message template order

**Request Payload Structure**

```json
{
  "endpoint": 8,
  "method": 3,
  "uuid": "123",
  "body": {
    "category": "template",
    "templateID": 2,
    "order": 3
  }
}
```

**Response Payload Structure**

```json
{
  "endpoint": 8,
  "status": 204,
  "uuid": 123
}
```

### Add a message template

**Request Payload Structure**

```json
{
  "endpoint": 8,
  "method": 2,
  "uuid": 123,
  "body": {
    "category": "template",
    "templateBody": "This is a new message template."
  }
}
```

**Response Payload Structure**

```json
{
  "body": {
    "templateID": 2
  },
  "endpoint": 8,
  "status": 200,
  "uuid": 123
}
```

### Delete a message template by id

**Request Payload Structure**

```json
{
  "endpoint": 8,
  "method": 4,
  "uuid": 123,
  "body": {
    "category": "template",
    "templateID": 2
  }
}
```

**Response Payload Structure**

```json
{
  "endpoint": 8,
  "status": 204,
  "uuid": 123
}
```
\ No newline at end of file

M module-db/Interface/ContactRecord.cpp => module-db/Interface/ContactRecord.cpp +15 -12
@@ 1276,26 1276,26 @@ auto ContactRecordInterface::GetBySpeedDial(const UTF8 &speedDial) -> std::uniqu
    return GetLimitOffsetByField(0, 1, ContactRecordField::SpeedDial, speedDial.c_str());
}

auto ContactRecordInterface::getNumbers(const std::string &numbers_id) -> std::vector<ContactRecord::Number>
auto ContactRecordInterface::getNumbers(const std::string &numbersId) -> std::vector<ContactRecord::Number>
{
    std::vector<ContactRecord::Number> nrs;
    for (const auto &nr_str : utils::split(numbers_id, ' ')) {
        auto nr_val = 0L;
    for (const auto &nrStr : utils::split(numbersId, ' ')) {
        auto nrVal = 0L;
        try {
            nr_val = std::stol(nr_str);
            nrVal = std::stol(nrStr);
        }
        catch (const std::exception &e) {
            error_db_data("Convertion error from %s, taking default value %ld", nr_str.c_str(), nr_val);
            error_db_data("Convertion error from %s, taking default value %ld", nrStr.c_str(), nrVal);
        }

        auto nr = contactDB->number.getById(nr_val);
        auto nr = contactDB->number.getById(nrVal);
        if (!nr.isValid()) {
            return nrs;
        }
        try {
            auto &&number = nr.numbere164.empty() ? utils::PhoneNumber(nr.numberUser, utils::country::Id::UNKNOWN)
                                                  : utils::PhoneNumber(nr.numberUser, nr.numbere164);
            nrs.emplace_back(number.getView(), nr.type);
            nrs.emplace_back(number.getView(), nr.type, nrVal);
        }
        catch (const utils::PhoneNumber::Error &e) {
            error_db_data(


@@ 1303,7 1303,7 @@ auto ContactRecordInterface::getNumbers(const std::string &numbers_id) -> std::v
                e.what(),
                nr.numberUser.c_str(),
                nr.numbere164.c_str());
            nrs.emplace_back(utils::PhoneNumber(nr.numberUser, utils::country::Id::UNKNOWN).getView(), nr.type);
            nrs.emplace_back(utils::PhoneNumber(nr.numberUser, utils::country::Id::UNKNOWN).getView(), nr.type, nrVal);
        }
    }
    return nrs;


@@ 1311,12 1311,15 @@ auto ContactRecordInterface::getNumbers(const std::string &numbers_id) -> std::v

ContactRecord::Number::Number() = default;

ContactRecord::Number::Number(const std::string &entered, const std::string &e164, ContactNumberType n_type)
    : number(utils::PhoneNumber(entered, e164).getView()), numberType(n_type)
ContactRecord::Number::Number(const std::string &entered,
                              const std::string &e164,
                              ContactNumberType n_type,
                              const std::uint64_t id)
    : number(utils::PhoneNumber(entered, e164).getView()), numberType(n_type), numberId(id)
{}

ContactRecord::Number::Number(const utils::PhoneNumber::View &number, ContactNumberType n_type)
    : number(number), numberType(n_type)
ContactRecord::Number::Number(const utils::PhoneNumber::View &number, ContactNumberType n_type, const std::uint64_t id)
    : number(number), numberType(n_type), numberId(id)
{}

auto ContactRecordInterface::getAllNumbers() -> const std::vector<ContactsNumberTableRow>

M module-db/Interface/ContactRecord.hpp => module-db/Interface/ContactRecord.hpp +10 -5
@@ 32,11 32,15 @@ struct ContactRecord : public Record
    {
        utils::PhoneNumber::View number;
        ContactNumberType numberType = ContactNumberType::OTHER;
        std::uint64_t numberId       = 0;
        Number();
        explicit Number(const utils::PhoneNumber::View &number, ContactNumberType = ContactNumberType::CELL);
        explicit Number(const utils::PhoneNumber::View &number,
                        ContactNumberType      = ContactNumberType::CELL,
                        const std::uint64_t id = 0);
        explicit Number(const std::string &entered,
                        const std::string &e164,
                        ContactNumberType n_type = ContactNumberType::CELL);
                        ContactNumberType n_type = ContactNumberType::CELL,
                        const std::uint64_t id   = 0);
    };
    std::vector<Number> numbers = {};



@@ 257,8 261,8 @@ class ContactRecordInterface : public RecordInterface<ContactRecord, ContactReco
  private:
    ContactsDB *contactDB = nullptr;

    /// get multiple numbers by split numbers_id
    auto getNumbers(const std::string &numbers_id) -> std::vector<ContactRecord::Number>;
    /// get multiple numbers by split numbersId
    auto getNumbers(const std::string &numbersId) -> std::vector<ContactRecord::Number>;
    auto getByIdCommon(ContactsTableRow &contact) -> ContactRecord;
    auto getContactByNumber(const UTF8 &number) -> const std::unique_ptr<std::vector<ContactRecord>>;
    auto getAllNumbers() -> const std::vector<ContactsNumberTableRow>;


@@ 305,7 309,8 @@ class ContactRecordInterface : public RecordInterface<ContactRecord, ContactReco
    auto matchedNumberRefersToTemporary(const ContactNumberHolder &matchedNumber) -> bool;

    /**
     * @brief Changing number table record in place if new number is same as old number but with/without country code
     * @brief Changing number table record in place if new number is same as old number but with/without country
     * code
     *
     * @param oldNumberIDs vector of old number IDs in contact_number table which can be changed in place
     *                     only if in  newNumbers  is same number but with/without country code

M products/PurePhone/services/desktop/endpoints/contacts/ContactHelper.cpp => products/PurePhone/services/desktop/endpoints/contacts/ContactHelper.cpp +6 -3
@@ 1,4 1,4 @@
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include <endpoints/contacts/ContactHelper.hpp>


@@ 32,10 32,12 @@ namespace sdesktop::endpoints

    auto ContactHelper::to_json(const ContactRecord &record) -> json11::Json
    {
        auto numberArray = json11::Json::array();
        auto numberArray   = json11::Json::array();
        auto numberIDArray = json11::Json::array();

        for (const auto &number : record.numbers) {
            numberArray.emplace_back(number.number.getEntered().c_str());
            numberIDArray.emplace_back(std::to_string(number.numberId).c_str());
        }

        auto recordEntry = json11::Json::object{{json::contacts::primaryName, record.primaryName.c_str()},


@@ 48,7 50,8 @@ namespace sdesktop::endpoints
                                                {json::contacts::isFavourite, record.isOnFavourites()},
                                                {json::contacts::isICE, record.isOnIce()},
                                                {json::contacts::speedDial, record.speeddial.c_str()},
                                                {json::contacts::numbers, numberArray}};
                                                {json::contacts::numbers, numberArray},
                                                {json::contacts::numbersIDs, numberIDArray}};
        return recordEntry;
    }


M products/PurePhone/services/desktop/endpoints/include/endpoints/contacts/ContactHelper.hpp => products/PurePhone/services/desktop/endpoints/include/endpoints/contacts/ContactHelper.hpp +2 -1
@@ 1,4 1,4 @@
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 41,6 41,7 @@ namespace sdesktop::endpoints
        inline constexpr auto mail            = "email";
        inline constexpr auto id              = "id";
        inline constexpr auto numbers         = "numbers";
        inline constexpr auto numbersIDs      = "numbersIDs";
        inline constexpr auto isBlocked       = "blocked";
        inline constexpr auto isFavourite     = "favourite";
        inline constexpr auto isICE           = "ice";

M products/PurePhone/services/desktop/endpoints/messages/MessageHelper.cpp => products/PurePhone/services/desktop/endpoints/messages/MessageHelper.cpp +2 -1
@@ 1,4 1,4 @@
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include <endpoints/messages/MessageHelper.hpp>


@@ 75,6 75,7 @@ namespace sdesktop::endpoints
    {

        auto recordEntry = json11::Json::object{{json::messages::number, number.getFormatted()},
                                                {json::messages::numberID, std::to_string(thread.numberID).c_str()},
                                                {json::messages::lastUpdatedAt, static_cast<int>(thread.date)},
                                                {json::messages::messageCount, static_cast<int>(thread.msgCount)},
                                                {json::messages::threadID, static_cast<int>(thread.ID)},

M pure_changelog.md => pure_changelog.md +31 -5
@@ 1,18 1,23 @@
# MuditaOS changelog - PurePhone

## Unreleased

### Added

* Always display network access technology and signal strength on the status bar
* Added days of the week to the list of SMS, calls and notes
* Added date formatting of received/sent SMS

### Changed / Improved

* Improved dialog with network via USSD
* Added serial number and timestamp to crashdump filename
* Changed order of starting services, ServiceDesktop moved to the back
* Shortened duration of phone modes pop-up from 3s to 1s
* Changed responses in contacts and messages endpoints used to communicate with Center

### Fixed

* Fixed not marking thread as read when new message arrives in the opened thread
* Fixed disappearing "confirm" button in PIN entering screen
* Fixed looping on the SIM card selection screen


@@ 30,7 35,7 @@
* Fixed message content being deleted when phone mode changed on new message window
* Fixed wrong navigation bar state after exit from custom repeat window
* Fixed OS crash when editing contact by adding country prefix to number
* Fixed unwanted Mudita Center passcode prompt after long press '#' while dialing 
* Fixed unwanted Mudita Center passcode prompt after long press '#' while dialing
* Fixed inability to unblock SIM card when previously ejected during slot switching
* Fixed French translations for Ulock Screen
* Fixed crash when syncing with Mudita Center


@@ 47,7 52,7 @@
* Fixed broken French translation on 'Configure passcode' screen in Onboarding
* Fixed time disappearing in SMS thread
* Fixed scrollbar behavior in call log view
* Fixed contacts imported from SIM not showing up in Mudita Center 
* Fixed contacts imported from SIM not showing up in Mudita Center
* Fixed broken events counter on main screen for more than 99 events
* Fixed incorrect signal strength displayed in Center
* Fixed inability to enter text in search field after clicking right arrow


@@ 60,7 65,7 @@
* Fixed inability to import contacts from Orange SIM cards
* Fixed SMS notification behaviour when only one thread is unread
* Fixed improper asterisk button behavior when adding new contact
* Fixed for contacts removed and imported from SIM card once again were added to database without names 
* Fixed for contacts removed and imported from SIM card once again were added to database without names
* Fixed (removed) redundant leading zero from time representation unless exactly midnight
* Fixed inability to type characters other than digits in USSD replies
* Fixed screen ghosting after emoji selection


@@ 72,18 77,26 @@
### Added

#### Messages:

* Added text message support via VoLTE modem.

#### Calls:

* Call support via VoLTE for users in the US

#### Home Screen:

* Added tethering info on status bar.

### Changed / Improved

#### SIM Cards:

* Change windows flow in SIM settings.
* Improved support for reinserting the SIM card into the device during SIM setup.

### Fixed

* Fixed MTP integration.
* Fixed incorrect total CPU usage in logs.
* Fixed disappearing button in PIN entering screen.


@@ 94,13 107,16 @@
* Fixed access to the phone before going onboarding.
* Fixed the phone hanging up after receiving an empty SMS message.


## [1.4.0 2022-10-06]

### Added

#### MMS:

* Added basic MMS handling.

#### Bluetooth:

* Added state refresh when BT automatically turns off.

### Changed / Improved


@@ 120,6 136,7 @@
* Separated system volume from Bluetooth device volume for A2DP.

### Fixed

* Fixed issue with music not pausing when BT device is disconnected.
* Fixed music player behaviour when connecting/disconnecting audio devices.
* Fixed issue with message handling in which characters not supported by Pure appear.


@@ 153,7 170,6 @@
* Fixed incorrect navigation text in onboarding for timezone and date time.
* Fixed wrong time displayed on password locked screen with 'Quotes' or 'Logo' wallpaper.


## [1.3.0 2022-08-04]

### Added


@@ 236,6 252,7 @@
## [1.2.1 2022-06-10]

### Improved

* Improved audio quality

## [1.2.0 2022-04-01]


@@ 243,23 260,29 @@
### Added

#### Quotes:

* Possibility to set periodically drawn quotes as wallpaper - predefined and custom.

#### Messages:

* Text writing option - "Abc" mode.

#### Contacts:

* Functionality to support the display of long contact names.

#### General:

* Extended time for displaying instructions to unlock the device.

#### Music Player:

* Extended audio files format support.

### Changed / Improved

#### General:

* Changed the default text input type from ABC mode to Abc mode.

### Fixed


@@ 301,6 324,7 @@
## [1.1.6 2022-01-20]

### Changed / Improved

* Changed speaker equalizer settings.

### Fixed


@@ 339,10 363,12 @@
* Fixed problem with contacts disappearing after editing them.

## [1.0.2 2021-11-08]

## [1.0.1 2021-11-08]

1.0.2 has the same scope as 1.0.1, we released it due to the minor issue with the version name in 1.0.1.

### Fixed

* Fixed problem with contacts disappearing after editing them.
* Fixed problem with MTP on Windows.