github.com/cozy/cozy-stack@v0.0.0-20240603063001-31110fa4cae1/model/vfs/cozy_metadata.go (about)

     1  package vfs
     2  
     3  import (
     4  	"time"
     5  
     6  	"github.com/cozy/cozy-stack/pkg/metadata"
     7  )
     8  
     9  // DocTypeVersion represents the doctype version. Each time this document
    10  // structure is modified, update this value
    11  const DocTypeVersion = "1"
    12  
    13  // UploadedByEntry is a struct with information on the app that has done the
    14  // last upload of a file.
    15  type UploadedByEntry struct {
    16  	Slug    string            `json:"slug,omitempty"`
    17  	Version string            `json:"version,omitempty"`
    18  	Client  map[string]string `json:"oauthClient,omitempty"`
    19  }
    20  
    21  // FilesCozyMetadata is an extended version of cozyMetadata with some specific fields.
    22  type FilesCozyMetadata struct {
    23  	metadata.CozyMetadata
    24  	// Instance URL where the file has been created
    25  	CreatedOn string `json:"createdOn,omitempty"`
    26  	// Date of the last upload of a new content
    27  	UploadedAt *time.Time `json:"uploadedAt,omitempty"`
    28  	// Information about the last time the content was uploaded
    29  	UploadedBy *UploadedByEntry `json:"uploadedBy,omitempty"`
    30  	// Instance URL where the content has been changed the last time
    31  	UploadedOn string `json:"uploadedOn,omitempty"`
    32  }
    33  
    34  // NewCozyMetadata initializes a new FilesCozyMetadata struct
    35  func NewCozyMetadata(instance string) *FilesCozyMetadata {
    36  	now := time.Now()
    37  	return &FilesCozyMetadata{
    38  		CozyMetadata: metadata.CozyMetadata{
    39  			DocTypeVersion:  DocTypeVersion,
    40  			MetadataVersion: metadata.MetadataVersion,
    41  			CreatedAt:       now,
    42  			UpdatedAt:       now,
    43  		},
    44  		CreatedOn: instance,
    45  	}
    46  }
    47  
    48  // Clone clones a FileCozyMetadata struct
    49  func (fcm *FilesCozyMetadata) Clone() *FilesCozyMetadata {
    50  	cloned := *fcm
    51  	cloned.UpdatedByApps = make([]*metadata.UpdatedByAppEntry, len(fcm.UpdatedByApps))
    52  	copy(cloned.UpdatedByApps, fcm.UpdatedByApps)
    53  	if fcm.UploadedBy != nil {
    54  		client := make(map[string]string)
    55  		for k, v := range fcm.UploadedBy.Client {
    56  			client[k] = v
    57  		}
    58  		cloned.UploadedBy = &UploadedByEntry{
    59  			Slug:    fcm.UploadedBy.Slug,
    60  			Version: fcm.UploadedBy.Version,
    61  			Client:  client,
    62  		}
    63  	}
    64  	if fcm.UploadedAt != nil {
    65  		at := *fcm.UploadedAt
    66  		cloned.UploadedAt = &at
    67  	}
    68  	return &cloned
    69  }
    70  
    71  // UpdatedByApp updates the list of UpdatedByApps entries with the new entry.
    72  // It ensures that each entry has a unique slug+instance, and the new entry
    73  // will be in the last position.
    74  func (fcm *FilesCozyMetadata) UpdatedByApp(entry *metadata.UpdatedByAppEntry) {
    75  	if entry.Slug == "" {
    76  		return
    77  	}
    78  
    79  	i := 0
    80  	seen := make(map[string]struct{})
    81  	for _, app := range fcm.UpdatedByApps {
    82  		if app.Slug == entry.Slug && app.Instance == entry.Instance {
    83  			continue
    84  		}
    85  		key := app.Slug + "/" + app.Instance
    86  		if _, ok := seen[key]; ok {
    87  			continue
    88  		}
    89  		fcm.UpdatedByApps[i] = app
    90  		seen[key] = struct{}{}
    91  		i++
    92  	}
    93  
    94  	fcm.UpdatedByApps = append(fcm.UpdatedByApps[:i], entry)
    95  }
    96  
    97  // ToJSONDoc returns a map with the cozyMetadata to be used inside a JSONDoc
    98  // (typically for sendings sharing updates).
    99  func (fcm *FilesCozyMetadata) ToJSONDoc() map[string]interface{} {
   100  	doc := make(map[string]interface{})
   101  	doc["doctypeVersion"] = fcm.DocTypeVersion
   102  	doc["metadataVersion"] = fcm.MetadataVersion
   103  	doc["createdAt"] = fcm.CreatedAt
   104  	if fcm.CreatedByApp != "" {
   105  		doc["createdByApp"] = fcm.CreatedByApp
   106  	}
   107  	if fcm.CreatedByAppVersion != "" {
   108  		doc["createdByAppVersion"] = fcm.CreatedByAppVersion
   109  	}
   110  	if fcm.CreatedOn != "" {
   111  		doc["createdOn"] = fcm.CreatedOn
   112  	}
   113  
   114  	doc["updatedAt"] = fcm.UpdatedAt
   115  	if len(fcm.UpdatedByApps) > 0 {
   116  		entries := make([]map[string]interface{}, len(fcm.UpdatedByApps))
   117  		for i, entry := range fcm.UpdatedByApps {
   118  			subdoc := map[string]interface{}{
   119  				"slug": entry.Slug,
   120  				"date": entry.Date,
   121  			}
   122  			if entry.Version != "" {
   123  				subdoc["version"] = entry.Version
   124  			}
   125  			if entry.Instance != "" {
   126  				subdoc["instance"] = entry.Instance
   127  			}
   128  			entries[i] = subdoc
   129  		}
   130  		doc["uploadedByApp"] = entries
   131  	}
   132  
   133  	if fcm.UploadedAt != nil {
   134  		doc["uploadedAt"] = *fcm.UploadedAt
   135  	}
   136  	if fcm.UploadedBy != nil {
   137  		uploaded := make(map[string]interface{})
   138  		if fcm.UploadedBy.Slug != "" {
   139  			uploaded["slug"] = fcm.UploadedBy.Slug
   140  		}
   141  		if fcm.UploadedBy.Version != "" {
   142  			uploaded["slug"] = fcm.UploadedBy.Version
   143  		}
   144  		if len(fcm.UploadedBy.Client) > 0 {
   145  			uploaded["oauthClient"] = fcm.UploadedBy.Client
   146  		}
   147  		doc["uploadedBy"] = uploaded
   148  	}
   149  	if fcm.UploadedOn != "" {
   150  		doc["uploadedOn"] = fcm.UploadedOn
   151  	}
   152  	if fcm.SourceAccount != "" {
   153  		doc["sourceAccount"] = fcm.SourceAccount
   154  	}
   155  	if fcm.SourceIdentifier != "" {
   156  		doc["sourceAccountIdentifier"] = fcm.SourceIdentifier
   157  	}
   158  	return doc
   159  }