mirror of
https://github.com/PeernetOfficial/core.git
synced 2026-07-17 02:47:51 +01:00
Simplified profile code.
This commit is contained in:
@@ -86,27 +86,6 @@ type apiBlockchainBlock struct {
|
||||
RecordsDecoded []interface{} `json:"recordsdecoded"` // Records decoded. The encoding for each record depends on its type.
|
||||
}
|
||||
|
||||
// apiBlockRecordProfile contains end-user information. Any data is treated as untrusted and unverified by default.
|
||||
type apiBlockRecordProfile struct {
|
||||
Fields []apiBlockRecordProfileField `json:"fields"` // All fields
|
||||
Blobs []apiBlockRecordProfileBlob `json:"blobs"` // Blobs
|
||||
}
|
||||
|
||||
// apiBlockRecordProfileField contains a single information about the end user. The data is always UTF8 text encoded.
|
||||
// Note that all profile data is arbitrary and shall be considered untrusted and unverified.
|
||||
// To establish trust, the user must load Certificates into the blockchain that validate certain data.
|
||||
type apiBlockRecordProfileField struct {
|
||||
Type uint16 `json:"type"` // See ProfileFieldX constants.
|
||||
Text string `json:"text"` // The data
|
||||
}
|
||||
|
||||
// apiBlockRecordProfileBlob is similar to apiBlockRecordProfileField but contains binary objects instead of text.
|
||||
// It can be used for example to store a profile picture on the blockchain.
|
||||
type apiBlockRecordProfileBlob struct {
|
||||
Type uint16 `json:"type"` // See ProfileBlobX constants.
|
||||
Data []byte `json:"data"` // The data
|
||||
}
|
||||
|
||||
// apiFileMetadata contains metadata information.
|
||||
type apiFileMetadata struct {
|
||||
Type uint16 `json:"type"` // See core.TagX constants.
|
||||
|
||||
@@ -15,68 +15,63 @@ import (
|
||||
|
||||
// apiProfileData contains profile metadata stored on the blockchain. Any data is treated as untrusted and unverified by default.
|
||||
type apiProfileData struct {
|
||||
Fields []apiBlockRecordProfileField `json:"fields"` // All fields
|
||||
Blobs []apiBlockRecordProfileBlob `json:"blobs"` // All blobs
|
||||
Status int `json:"status"` // Status of the operation, only used when this structure is returned from the API. See core.BlockchainStatusX.
|
||||
Fields []apiBlockRecordProfile `json:"fields"` // All fields
|
||||
Status int `json:"status"` // Status of the operation, only used when this structure is returned from the API. See core.BlockchainStatusX.
|
||||
}
|
||||
|
||||
// apiBlockRecordProfile provides information about the end user. Note that all profile data is arbitrary and shall be considered untrusted and unverified.
|
||||
// To establish trust, the user must load Certificates into the blockchain that validate certain data.
|
||||
type apiBlockRecordProfile struct {
|
||||
Type uint16 `json:"type"` // See ProfileX constants.
|
||||
// Depending on the exact type, one of the below fields is used for proper encoding:
|
||||
Text string `json:"text"` // Text value. UTF-8 encoding.
|
||||
Blob []byte `json:"blob"` // Binary data
|
||||
}
|
||||
|
||||
/*
|
||||
apiProfileList lists all users profile fields and blobs.
|
||||
apiProfileList lists all users profile fields.
|
||||
|
||||
Request: GET /profile/list
|
||||
Response: 200 with JSON structure apiProfileData
|
||||
*/
|
||||
func apiProfileList(w http.ResponseWriter, r *http.Request) {
|
||||
fields, blobs, status := core.UserProfileList()
|
||||
fields, status := core.UserProfileList()
|
||||
|
||||
result := apiProfileData{Status: status}
|
||||
for n := range fields {
|
||||
result.Fields = append(result.Fields, apiBlockRecordProfileField{Type: fields[n].Type, Text: fields[n].Text})
|
||||
}
|
||||
for n := range blobs {
|
||||
result.Blobs = append(result.Blobs, apiBlockRecordProfileBlob{Type: blobs[n].Type, Data: blobs[n].Data})
|
||||
result.Fields = append(result.Fields, blockRecordProfileToAPI(fields[n]))
|
||||
}
|
||||
|
||||
EncodeJSON(w, r, result)
|
||||
}
|
||||
|
||||
/*
|
||||
apiProfileRead reads a specific users profile field or blob.
|
||||
For the index see core.ProfileFieldX and core.ProfileBlobX constants.
|
||||
apiProfileRead reads a specific users profile field. See core.ProfileX for recognized fields.
|
||||
|
||||
Request: GET /profile/read?field=[index] or &blob=[index]
|
||||
Request: GET /profile/read?field=[index]
|
||||
Response: 200 with JSON structure apiProfileData
|
||||
*/
|
||||
func apiProfileRead(w http.ResponseWriter, r *http.Request) {
|
||||
r.ParseForm()
|
||||
fieldN, err1 := strconv.Atoi(r.Form.Get("field"))
|
||||
blobN, err2 := strconv.Atoi(r.Form.Get("blob"))
|
||||
|
||||
if (err1 != nil && err2 != nil) || (err1 == nil && fieldN < 0) || (err2 == nil && blobN < 0) {
|
||||
if err1 != nil || fieldN < 0 {
|
||||
http.Error(w, "", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
var result apiProfileData
|
||||
|
||||
if err1 == nil {
|
||||
var text string
|
||||
if text, result.Status = core.UserProfileReadField(uint16(fieldN)); result.Status == core.BlockchainStatusOK {
|
||||
result.Fields = append(result.Fields, apiBlockRecordProfileField{Type: uint16(fieldN), Text: text})
|
||||
}
|
||||
} else {
|
||||
var data []byte
|
||||
if data, result.Status = core.UserProfileReadBlob(uint16(blobN)); result.Status == core.BlockchainStatusOK {
|
||||
result.Blobs = append(result.Blobs, apiBlockRecordProfileBlob{Type: uint16(blobN), Data: data})
|
||||
}
|
||||
var data []byte
|
||||
if data, result.Status = core.UserProfileReadField(uint16(fieldN)); result.Status == core.BlockchainStatusOK {
|
||||
result.Fields = append(result.Fields, blockRecordProfileToAPI(core.BlockRecordProfile{Type: uint16(fieldN), Data: data}))
|
||||
}
|
||||
|
||||
EncodeJSON(w, r, result)
|
||||
}
|
||||
|
||||
/*
|
||||
apiProfileWrite writes profile fields or blobs.
|
||||
For the index see core.ProfileFieldX and core.ProfileBlobX constants.
|
||||
apiProfileWrite writes profile fields. See core.ProfileX for recognized fields.
|
||||
|
||||
Request: POST /profile/write with JSON structure apiProfileData
|
||||
Response: 200 with JSON structure apiBlockchainBlockStatus
|
||||
@@ -87,23 +82,19 @@ func apiProfileWrite(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
var profile core.BlockRecordProfile
|
||||
var fields []core.BlockRecordProfile
|
||||
|
||||
for n := range input.Fields {
|
||||
profile.Fields = append(profile.Fields, core.BlockRecordProfileField{Type: input.Fields[n].Type, Text: input.Fields[n].Text})
|
||||
}
|
||||
for n := range input.Blobs {
|
||||
profile.Blobs = append(profile.Blobs, core.BlockRecordProfileBlob{Type: input.Blobs[n].Type, Data: input.Blobs[n].Data})
|
||||
fields = append(fields, blockRecordProfileFromAPI(input.Fields[n]))
|
||||
}
|
||||
|
||||
newHeight, newVersion, status := core.UserProfileWrite(profile)
|
||||
newHeight, newVersion, status := core.UserProfileWrite(fields)
|
||||
|
||||
EncodeJSON(w, r, apiBlockchainBlockStatus{Status: status, Height: newHeight, Version: newVersion})
|
||||
}
|
||||
|
||||
/*
|
||||
apiProfileDelete deletes profile fields or blobs identified by the types.
|
||||
For the index see core.ProfileFieldX and core.ProfileBlobX constants.
|
||||
apiProfileDelete deletes profile fields identified by the types. See core.ProfileX for recognized fields.
|
||||
|
||||
Request: POST /profile/delete with JSON structure apiProfileData
|
||||
Response: 200 with JSON structure apiBlockchainBlockStatus
|
||||
@@ -114,16 +105,13 @@ func apiProfileDelete(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
var fields, blobs []uint16
|
||||
var fields []uint16
|
||||
|
||||
for n := range input.Fields {
|
||||
fields = append(fields, input.Fields[n].Type)
|
||||
}
|
||||
for n := range input.Blobs {
|
||||
blobs = append(blobs, input.Blobs[n].Type)
|
||||
}
|
||||
|
||||
newHeight, newVersion, status := core.UserProfileDelete(fields, blobs)
|
||||
newHeight, newVersion, status := core.UserProfileDelete(fields)
|
||||
|
||||
EncodeJSON(w, r, apiBlockchainBlockStatus{Status: status, Height: newHeight, Version: newVersion})
|
||||
}
|
||||
@@ -131,22 +119,34 @@ func apiProfileDelete(w http.ResponseWriter, r *http.Request) {
|
||||
// --- conversion from core to API data ---
|
||||
|
||||
func blockRecordProfileToAPI(input core.BlockRecordProfile) (output apiBlockRecordProfile) {
|
||||
for n := range input.Fields {
|
||||
output.Fields = append(output.Fields, apiBlockRecordProfileField{Type: input.Fields[n].Type, Text: input.Fields[n].Text})
|
||||
}
|
||||
for n := range input.Blobs {
|
||||
output.Blobs = append(output.Blobs, apiBlockRecordProfileBlob{Type: input.Blobs[n].Type, Data: input.Blobs[n].Data})
|
||||
output.Type = input.Type
|
||||
|
||||
switch input.Type {
|
||||
case core.ProfileName, core.ProfileEmail, core.ProfileWebsite, core.ProfileTwitter, core.ProfileYouTube, core.ProfileAddress:
|
||||
output.Text = input.Text()
|
||||
|
||||
case core.ProfilePicture:
|
||||
output.Blob = input.Data
|
||||
|
||||
default:
|
||||
output.Blob = input.Data
|
||||
}
|
||||
|
||||
return output
|
||||
}
|
||||
|
||||
func blockRecordProfileFromAPI(input apiBlockRecordProfile) (output core.BlockRecordProfile) {
|
||||
for n := range input.Fields {
|
||||
output.Fields = append(output.Fields, core.BlockRecordProfileField{Type: input.Fields[n].Type, Text: input.Fields[n].Text})
|
||||
}
|
||||
for n := range input.Blobs {
|
||||
output.Blobs = append(output.Blobs, core.BlockRecordProfileBlob{Type: input.Blobs[n].Type, Data: input.Blobs[n].Data})
|
||||
output.Type = input.Type
|
||||
|
||||
switch input.Type {
|
||||
case core.ProfileName, core.ProfileEmail, core.ProfileWebsite, core.ProfileTwitter, core.ProfileYouTube, core.ProfileAddress:
|
||||
output.Data = []byte(input.Text)
|
||||
|
||||
case core.ProfilePicture:
|
||||
output.Data = input.Blob
|
||||
|
||||
default:
|
||||
output.Data = input.Blob
|
||||
}
|
||||
|
||||
return output
|
||||
|
||||
111
webapi/readme.md
111
webapi/readme.md
@@ -37,10 +37,10 @@ These are the functions provided by the API:
|
||||
/blockchain/self/list/file List all files stored on the blockchain
|
||||
/blockchain/self/delete/file Delete files from the blockchain
|
||||
|
||||
/profile/list List all users profile fields and blobs
|
||||
/profile/read Read a profile field or blob
|
||||
/profile/write Write profile fields or blobs
|
||||
/profile/delete Delete profile fields or blobs
|
||||
/profile/list List all profile fields
|
||||
/profile/read Read a profile field
|
||||
/profile/write Write profile fields
|
||||
/profile/delete Delete profile fields
|
||||
|
||||
/search Submit a search request
|
||||
/search/result Return search results
|
||||
@@ -98,6 +98,18 @@ type apiResponsePeerSelf struct {
|
||||
|
||||
## Blockchain Functions
|
||||
|
||||
Common status codes returned by various endpoints:
|
||||
|
||||
```go
|
||||
const (
|
||||
BlockchainStatusOK = 0 // No problems in the blockchain detected.
|
||||
BlockchainStatusBlockNotFound = 1 // Missing block in the blockchain.
|
||||
BlockchainStatusCorruptBlock = 2 // Error block encoding
|
||||
BlockchainStatusCorruptBlockRecord = 3 // Error block record encoding
|
||||
BlockchainStatusDataNotFound = 4 // Requested data not available in the blockchain
|
||||
)
|
||||
```
|
||||
|
||||
### Blockchain Self Header
|
||||
|
||||
This function returns information about the current peer. It is not required that a peer has a blockchain. If no data is shared, there are no blocks. The blockchain does not formally have a header as each block has the same structure.
|
||||
@@ -167,23 +179,6 @@ The array `RecordsDecoded` will contain any present record of the following:
|
||||
* Profile records, see `apiBlockRecordProfile`
|
||||
* File records, see `apiBlockRecordFile`
|
||||
|
||||
```go
|
||||
type apiBlockRecordProfile struct {
|
||||
Fields []apiBlockRecordProfileField `json:"fields"` // All fields
|
||||
Blobs []apiBlockRecordProfileBlob `json:"blobs"` // Blobs
|
||||
}
|
||||
|
||||
type apiBlockRecordProfileField struct {
|
||||
Type uint16 `json:"type"` // See ProfileFieldX constants.
|
||||
Text string `json:"text"` // The data
|
||||
}
|
||||
|
||||
type apiBlockRecordProfileBlob struct {
|
||||
Type uint16 `json:"type"` // See ProfileBlobX constants.
|
||||
Data []byte `json:"data"` // The data
|
||||
}
|
||||
```
|
||||
|
||||
## File Functions
|
||||
|
||||
These functions allow adding, deleting, and listing files stored on the users blockchain. Only metadata is actually stored on the blockchain.
|
||||
@@ -355,25 +350,26 @@ Example response:
|
||||
|
||||
## Profile Functions
|
||||
|
||||
User profile data such as the username, email address, and picture are stored on the blockchain. The Profile API distinguishes between text data (= fields) and binary data (= blobs). Text is UTF-8 encoded.
|
||||
User profile data such as the username, email address, and picture are stored on the blockchain. Profile fields are text (UTF-8) or binary encoded, depending on the type.
|
||||
|
||||
Below is the current list of well known profile information. Clients may define additional fields. The purpose of this defined list is to provide a common mapping across different client software. In the Go code they are defined as constants starting with `ProfileField` and `ProfileBlob`.
|
||||
Note that all profile data is arbitrary and shall be considered untrusted and unverified. To establish trust, the user must load Certificates into the blockchain that validate certain data.
|
||||
|
||||
| Field Identifier | Purpose |
|
||||
|------------------|----------------------------|
|
||||
| 0 | Username, arbitrary |
|
||||
| 1 | Email address |
|
||||
| 2 | Website address |
|
||||
| 3 | Twitter account with the @ |
|
||||
| 4 | YouTube channel URL |
|
||||
| 5 | Physical address |
|
||||
Below is the list of well known profile information. Clients may define additional fields. The purpose of this defined list is to provide a common mapping across different client software. Undefined types are always mapped into the `blob` field.
|
||||
|
||||
| Blob Identifier | Purpose |
|
||||
|------------------|----------------------------|
|
||||
| 0 | Profile picture, unspecified size |
|
||||
| Type | Constant | Encoding | Info |
|
||||
|------|----------------|----------|-------------------------------|
|
||||
| 0 | ProfileName | Text | Arbitrary username |
|
||||
| 1 | ProfileEmail | Text | Email address |
|
||||
| 2 | ProfileWebsite | Text | Website address |
|
||||
| 3 | ProfileTwitter | Text | Twitter account without the @ |
|
||||
| 4 | ProfileYouTube | Text | YouTube channel URL |
|
||||
| 5 | ProfileAddress | Text | Physical address |
|
||||
| 6 | ProfilePicture | Blob | Profile picture |
|
||||
|
||||
### Profile List
|
||||
|
||||
This lists all profile fields.
|
||||
|
||||
```
|
||||
Request: GET /profile/list
|
||||
Response: 200 with JSON structure apiProfileData
|
||||
@@ -381,18 +377,16 @@ Response: 200 with JSON structure apiProfileData
|
||||
|
||||
```go
|
||||
type apiProfileData struct {
|
||||
Fields []apiBlockRecordProfileField `json:"fields"` // All fields
|
||||
Blobs []apiBlockRecordProfileBlob `json:"blobs"` // All blobs
|
||||
Status int `json:"status"` // Status of the operation, only used when this structure is returned from the API. See core.BlockchainStatusX.
|
||||
Fields []apiBlockRecordProfile `json:"fields"` // All fields
|
||||
Status int `json:"status"` // Status of the operation, only used when this structure is returned from the API. See core.BlockchainStatusX.
|
||||
}
|
||||
|
||||
const (
|
||||
BlockchainStatusOK = 0 // No problems in the blockchain detected.
|
||||
BlockchainStatusBlockNotFound = 1 // Missing block in the blockchain.
|
||||
BlockchainStatusCorruptBlock = 2 // Error block encoding
|
||||
BlockchainStatusCorruptBlockRecord = 3 // Error block record encoding
|
||||
BlockchainStatusDataNotFound = 4 // Requested data not available in the blockchain
|
||||
)
|
||||
type apiBlockRecordProfile struct {
|
||||
Type uint16 `json:"type"` // See ProfileX constants.
|
||||
// Depending on the exact type, one of the below fields is used for proper encoding:
|
||||
Text string `json:"text"` // Text value. UTF-8 encoding.
|
||||
Blob []byte `json:"blob"` // Binary data
|
||||
}
|
||||
```
|
||||
|
||||
Example request: `http://127.0.0.1:112/profile/list`
|
||||
@@ -403,22 +397,23 @@ Example response:
|
||||
{
|
||||
"fields": [{
|
||||
"type": 0,
|
||||
"text": "Test Username 2022"
|
||||
"text": "Test Username 2021",
|
||||
"blob": null
|
||||
}, {
|
||||
"type": 1,
|
||||
"text": "test@example.com"
|
||||
"text": "test@example.com",
|
||||
"blob": null
|
||||
}],
|
||||
"blobs": null,
|
||||
"status": 0
|
||||
}
|
||||
```
|
||||
|
||||
### Profile Read
|
||||
|
||||
This reads a specific users' profile field or blob. For the index see the `ProfileFieldX` and `ProfileBlobX` constants.
|
||||
This reads a specific profile field. See ProfileX for recognized fields.
|
||||
|
||||
```
|
||||
Request: GET /profile/read?field=[index] or &blob=[index]
|
||||
Request: GET /profile/read?field=[index]
|
||||
Response: 200 with JSON structure apiProfileData
|
||||
```
|
||||
|
||||
@@ -430,16 +425,16 @@ Example response:
|
||||
{
|
||||
"fields": [{
|
||||
"type": 0,
|
||||
"text": "Test Username 2022"
|
||||
"text": "Test Username 2021",
|
||||
"blob": null
|
||||
}],
|
||||
"blobs": null,
|
||||
"status": 0
|
||||
}
|
||||
```
|
||||
|
||||
### Profile Write
|
||||
|
||||
This writes profile fields and blobs. It can write multiple fields and blobs at once.
|
||||
This writes profile fields. It can write multiple fields at once. See ProfileX for recognized fields.
|
||||
|
||||
```
|
||||
Request: POST /profile/write with JSON structure apiProfileData
|
||||
@@ -469,7 +464,7 @@ Example response:
|
||||
|
||||
### Profile Delete
|
||||
|
||||
This function allows to delete profile data (both fields and blobs). Only the type number in the fields and blobs are required. Multiple fields and blobs can be deleted at the same time.
|
||||
This function allows to delete profile fields. Only the type number is required. Multiple fields can be deleted at the same time.
|
||||
|
||||
```
|
||||
Request: POST /profile/delete with JSON structure apiProfileData
|
||||
@@ -486,16 +481,6 @@ Example POST request to `http://127.0.0.1:112/profile/delete` (deleting the prof
|
||||
}
|
||||
```
|
||||
|
||||
One practical use case is deleting the profile picture (by specifying blob 0) with the following payload:
|
||||
|
||||
```json
|
||||
{
|
||||
"blobs": [{
|
||||
"type": 0
|
||||
}]
|
||||
}
|
||||
```
|
||||
|
||||
## Search API
|
||||
|
||||
The search API provides a high-level function to search for files in Peernet. Searching is always asynchronous. `/search` returns an UUID which is used to loop over `/search/result` until the search is terminated.
|
||||
|
||||
Reference in New Issue
Block a user