mirror of
https://github.com/status-im/status-go.git
synced 2025-02-16 08:50:09 +00:00
feat: Profile showcase backend (#4005)
* feat: profile showcase preferences basic impl (squashed) * feat: save preferences in batch for profile showcase * chore: add validation for profile showcase settings request and fix migration order
This commit is contained in:
parent
e83be20def
commit
1be356af93
88
protocol/messenger_profile_showcase.go
Normal file
88
protocol/messenger_profile_showcase.go
Normal file
@ -0,0 +1,88 @@
|
||||
package protocol
|
||||
|
||||
import "fmt"
|
||||
|
||||
type ProfileShowcasePreferences struct {
|
||||
Communities []*ProfileShowcaseEntry `json:"communities"`
|
||||
Accounts []*ProfileShowcaseEntry `json:"accounts"`
|
||||
Collectibles []*ProfileShowcaseEntry `json:"collectibles"`
|
||||
Assets []*ProfileShowcaseEntry `json:"assets"`
|
||||
}
|
||||
|
||||
func (p *ProfileShowcasePreferences) Validate() error {
|
||||
for _, community := range p.Communities {
|
||||
if community.EntryType != ProfileShowcaseEntryTypeCommunity {
|
||||
return fmt.Errorf("communities must contain only entriers of type ProfileShowcaseEntryTypeCommunity")
|
||||
}
|
||||
}
|
||||
|
||||
for _, community := range p.Accounts {
|
||||
if community.EntryType != ProfileShowcaseEntryTypeAccount {
|
||||
return fmt.Errorf("accounts must contain only entriers of type ProfileShowcaseEntryTypeAccount")
|
||||
}
|
||||
}
|
||||
|
||||
for _, community := range p.Collectibles {
|
||||
if community.EntryType != ProfileShowcaseEntryTypeCollectible {
|
||||
return fmt.Errorf("collectibles must contain only entriers of type ProfileShowcaseEntryTypeCollectible")
|
||||
}
|
||||
}
|
||||
|
||||
for _, community := range p.Assets {
|
||||
if community.EntryType != ProfileShowcaseEntryTypeAsset {
|
||||
return fmt.Errorf("assets must contain only entriers of type ProfileShowcaseEntryTypeAsset")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Messenger) SetProfileShowcasePreference(entry *ProfileShowcaseEntry) error {
|
||||
return m.persistence.InsertOrUpdateProfileShowcasePreference(entry)
|
||||
}
|
||||
|
||||
func (m *Messenger) SetProfileShowcasePreferences(preferences ProfileShowcasePreferences) error {
|
||||
err := preferences.Validate()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
allPreferences := []*ProfileShowcaseEntry{}
|
||||
|
||||
allPreferences = append(allPreferences, preferences.Communities...)
|
||||
allPreferences = append(allPreferences, preferences.Accounts...)
|
||||
allPreferences = append(allPreferences, preferences.Collectibles...)
|
||||
allPreferences = append(allPreferences, preferences.Assets...)
|
||||
|
||||
return m.persistence.SaveProfileShowcasePreferences(allPreferences)
|
||||
}
|
||||
|
||||
func (m *Messenger) GetProfileShowcasePreferences() (*ProfileShowcasePreferences, error) {
|
||||
// NOTE: in the future default profile preferences should be filled in for each group according to special rules,
|
||||
// that's why they should be grouped here
|
||||
communities, err := m.persistence.GetProfileShowcasePreferencesByType(ProfileShowcaseEntryTypeCommunity)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
accounts, err := m.persistence.GetProfileShowcasePreferencesByType(ProfileShowcaseEntryTypeAccount)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
collectibles, err := m.persistence.GetProfileShowcasePreferencesByType(ProfileShowcaseEntryTypeCollectible)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
assets, err := m.persistence.GetProfileShowcasePreferencesByType(ProfileShowcaseEntryTypeAsset)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &ProfileShowcasePreferences{
|
||||
Communities: communities,
|
||||
Accounts: accounts,
|
||||
Collectibles: collectibles,
|
||||
Assets: assets,
|
||||
}, nil
|
||||
}
|
78
protocol/messenger_profile_showcase_test.go
Normal file
78
protocol/messenger_profile_showcase_test.go
Normal file
@ -0,0 +1,78 @@
|
||||
package protocol
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/suite"
|
||||
)
|
||||
|
||||
func TestMessengerProfileShowcaseSuite(t *testing.T) {
|
||||
suite.Run(t, new(MessengerProfileShowcaseSuite))
|
||||
}
|
||||
|
||||
type MessengerProfileShowcaseSuite struct {
|
||||
MessengerBaseTestSuite
|
||||
}
|
||||
|
||||
func (s *MessengerProfileShowcaseSuite) TestSetAndGetProfileShowcasePreferences() {
|
||||
communityEntry1 := &ProfileShowcaseEntry{
|
||||
ID: "0x01312357798976434",
|
||||
EntryType: ProfileShowcaseEntryTypeCommunity,
|
||||
ShowcaseVisibility: ProfileShowcaseVisibilityContacts,
|
||||
Order: 10,
|
||||
}
|
||||
|
||||
communityEntry2 := &ProfileShowcaseEntry{
|
||||
ID: "0x01312357798976535",
|
||||
EntryType: ProfileShowcaseEntryTypeCommunity,
|
||||
ShowcaseVisibility: ProfileShowcaseVisibilityEveryone,
|
||||
Order: 11,
|
||||
}
|
||||
|
||||
accountEntry := &ProfileShowcaseEntry{
|
||||
ID: "0cx34662234",
|
||||
EntryType: ProfileShowcaseEntryTypeAccount,
|
||||
ShowcaseVisibility: ProfileShowcaseVisibilityEveryone,
|
||||
Order: 17,
|
||||
}
|
||||
|
||||
collectibleEntry := &ProfileShowcaseEntry{
|
||||
ID: "0x12378534257568678487683576",
|
||||
EntryType: ProfileShowcaseEntryTypeCollectible,
|
||||
ShowcaseVisibility: ProfileShowcaseVisibilityIDVerifiedContacts,
|
||||
Order: 17,
|
||||
}
|
||||
|
||||
assetEntry := &ProfileShowcaseEntry{
|
||||
ID: "0x139ii4uu423",
|
||||
EntryType: ProfileShowcaseEntryTypeAsset,
|
||||
ShowcaseVisibility: ProfileShowcaseVisibilityNoOne,
|
||||
Order: 17,
|
||||
}
|
||||
|
||||
request := ProfileShowcasePreferences{
|
||||
Communities: []*ProfileShowcaseEntry{communityEntry1, communityEntry2},
|
||||
Accounts: []*ProfileShowcaseEntry{accountEntry},
|
||||
Collectibles: []*ProfileShowcaseEntry{collectibleEntry},
|
||||
Assets: []*ProfileShowcaseEntry{assetEntry},
|
||||
}
|
||||
|
||||
err := s.m.SetProfileShowcasePreferences(request)
|
||||
s.Require().NoError(err)
|
||||
|
||||
response, err := s.m.GetProfileShowcasePreferences()
|
||||
s.Require().NoError(err)
|
||||
|
||||
s.Require().Len(response.Communities, 2)
|
||||
s.Require().Equal(response.Communities[0], communityEntry1)
|
||||
s.Require().Equal(response.Communities[1], communityEntry2)
|
||||
|
||||
s.Require().Len(response.Accounts, 1)
|
||||
s.Require().Equal(response.Accounts[0], accountEntry)
|
||||
|
||||
s.Require().Len(response.Collectibles, 1)
|
||||
s.Require().Equal(response.Collectibles[0], collectibleEntry)
|
||||
|
||||
s.Require().Len(response.Assets, 1)
|
||||
s.Require().Equal(response.Assets[0], assetEntry)
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,13 @@
|
||||
CREATE TABLE IF NOT EXISTS profile_showcase_preferences (
|
||||
id TEXT PRIMARY KEY ON CONFLICT REPLACE,
|
||||
entry_type INT NOT NULL DEFAULT 0,
|
||||
visibility INT NOT NULL DEFAULT 0,
|
||||
sort_order INT NOT NULL DEFAULT 0
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS profile_showcase_contacts (
|
||||
contact_id TEXT PRIMARY KEY ON CONFLICT REPLACE,
|
||||
entry_id TEXT NOT NULL,
|
||||
entry_type INT NOT NULL DEFAULT 0,
|
||||
entry_order INT NOT NULL DEFAULT 0
|
||||
);
|
122
protocol/persistence_profile_showcase.go
Normal file
122
protocol/persistence_profile_showcase.go
Normal file
@ -0,0 +1,122 @@
|
||||
package protocol
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
)
|
||||
|
||||
type ProfileShowcaseEntryType int
|
||||
|
||||
const (
|
||||
ProfileShowcaseEntryTypeCommunity ProfileShowcaseEntryType = iota
|
||||
ProfileShowcaseEntryTypeAccount
|
||||
ProfileShowcaseEntryTypeCollectible
|
||||
ProfileShowcaseEntryTypeAsset
|
||||
)
|
||||
|
||||
type ProfileShowcaseVisibility int
|
||||
|
||||
const (
|
||||
ProfileShowcaseVisibilityNoOne ProfileShowcaseVisibility = iota
|
||||
ProfileShowcaseVisibilityIDVerifiedContacts
|
||||
ProfileShowcaseVisibilityContacts
|
||||
ProfileShowcaseVisibilityEveryone
|
||||
)
|
||||
|
||||
const insertOrUpdateProfilePreferencesQuery = "INSERT OR REPLACE INTO profile_showcase_preferences(id, entry_type, visibility, sort_order) VALUES (?, ?, ?, ?)"
|
||||
const selectAllProfilePreferencesQuery = "SELECT id, entry_type, visibility, sort_order FROM profile_showcase_preferences"
|
||||
const selectProfilePreferencesByTypeQuery = "SELECT id, entry_type, visibility, sort_order FROM profile_showcase_preferences WHERE entry_type = ?"
|
||||
|
||||
type ProfileShowcaseEntry struct {
|
||||
ID string `json:"id"`
|
||||
EntryType ProfileShowcaseEntryType `json:"entryType"`
|
||||
ShowcaseVisibility ProfileShowcaseVisibility `json:"showcaseVisibility"`
|
||||
Order int `json:"order"`
|
||||
}
|
||||
|
||||
func (db sqlitePersistence) InsertOrUpdateProfileShowcasePreference(entry *ProfileShowcaseEntry) error {
|
||||
_, err := db.db.Exec(insertOrUpdateProfilePreferencesQuery,
|
||||
entry.ID,
|
||||
entry.EntryType,
|
||||
entry.ShowcaseVisibility,
|
||||
entry.Order,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (db sqlitePersistence) SaveProfileShowcasePreferences(entries []*ProfileShowcaseEntry) error {
|
||||
tx, err := db.db.BeginTx(context.Background(), &sql.TxOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
if err == nil {
|
||||
err = tx.Commit()
|
||||
return
|
||||
}
|
||||
// don't shadow original error
|
||||
_ = tx.Rollback()
|
||||
}()
|
||||
|
||||
for _, entry := range entries {
|
||||
_, err = tx.Exec(insertOrUpdateProfilePreferencesQuery,
|
||||
entry.ID,
|
||||
entry.EntryType,
|
||||
entry.ShowcaseVisibility,
|
||||
entry.Order,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (db sqlitePersistence) parseProfileShowcasePreferencesRows(rows *sql.Rows) ([]*ProfileShowcaseEntry, error) {
|
||||
entries := []*ProfileShowcaseEntry{}
|
||||
|
||||
for rows.Next() {
|
||||
entry := &ProfileShowcaseEntry{}
|
||||
|
||||
err := rows.Scan(
|
||||
&entry.ID,
|
||||
&entry.EntryType,
|
||||
&entry.ShowcaseVisibility,
|
||||
&entry.Order,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
entries = append(entries, entry)
|
||||
}
|
||||
return entries, nil
|
||||
}
|
||||
|
||||
func (db sqlitePersistence) GetAllProfileShowcasePreferences() ([]*ProfileShowcaseEntry, error) {
|
||||
rows, err := db.db.Query(selectAllProfilePreferencesQuery)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
return db.parseProfileShowcasePreferencesRows(rows)
|
||||
}
|
||||
|
||||
func (db sqlitePersistence) GetProfileShowcasePreferencesByType(entryType ProfileShowcaseEntryType) ([]*ProfileShowcaseEntry, error) {
|
||||
rows, err := db.db.Query(selectProfilePreferencesByTypeQuery, entryType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
return db.parseProfileShowcasePreferencesRows(rows)
|
||||
}
|
@ -1546,6 +1546,16 @@ func (api *PublicAPI) CreateTokenGatedCommunity() (*protocol.MessengerResponse,
|
||||
return api.service.messenger.CreateTokenGatedCommunity()
|
||||
}
|
||||
|
||||
// Set profile showcase preference for current user
|
||||
func (api *PublicAPI) SetProfileShowcasePreferences(preferences protocol.ProfileShowcasePreferences) error {
|
||||
return api.service.messenger.SetProfileShowcasePreferences(preferences)
|
||||
}
|
||||
|
||||
// Get all profile showcase preferences for current user
|
||||
func (api *PublicAPI) GetProfileShowcasePreferences() (*protocol.ProfileShowcasePreferences, error) {
|
||||
return api.service.messenger.GetProfileShowcasePreferences()
|
||||
}
|
||||
|
||||
// -----
|
||||
// HELPER
|
||||
// -----
|
||||
|
Loading…
x
Reference in New Issue
Block a user