Adding in some basic boilerplate for groups service. --- #### Does this PR need a docs update or release note? - [x] ⛔ No #### Type of change - [x] 🌻 Feature
144 lines
3.1 KiB
Go
144 lines
3.1 KiB
Go
package details
|
|
|
|
import (
|
|
"sync"
|
|
|
|
"github.com/alcionai/clues"
|
|
"golang.org/x/exp/maps"
|
|
|
|
"github.com/alcionai/corso/src/pkg/path"
|
|
)
|
|
|
|
// Builder should be used to create a details model.
|
|
type Builder struct {
|
|
d Details
|
|
mu sync.Mutex `json:"-"`
|
|
knownFolders map[string]Entry `json:"-"`
|
|
}
|
|
|
|
func (b *Builder) Add(
|
|
repoRef path.Path,
|
|
locationRef *path.Builder,
|
|
updated bool,
|
|
info ItemInfo,
|
|
) error {
|
|
b.mu.Lock()
|
|
defer b.mu.Unlock()
|
|
|
|
entry, err := b.d.add(
|
|
repoRef,
|
|
locationRef,
|
|
updated,
|
|
info)
|
|
if err != nil {
|
|
return clues.Wrap(err, "adding entry to details")
|
|
}
|
|
|
|
if err := b.addFolderEntries(
|
|
repoRef.ToBuilder().Dir(),
|
|
locationRef,
|
|
entry,
|
|
); err != nil {
|
|
return clues.Wrap(err, "adding folder entries")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (b *Builder) addFolderEntries(
|
|
repoRef, locationRef *path.Builder,
|
|
entry Entry,
|
|
) error {
|
|
if len(repoRef.Elements()) < len(locationRef.Elements()) {
|
|
return clues.New("RepoRef shorter than LocationRef").
|
|
With("repo_ref", repoRef, "location_ref", locationRef)
|
|
}
|
|
|
|
if b.knownFolders == nil {
|
|
b.knownFolders = map[string]Entry{}
|
|
}
|
|
|
|
// Need a unique location because we want to have separate folders for
|
|
// different drives and categories even if there's duplicate folder names in
|
|
// them.
|
|
uniqueLoc, err := entry.uniqueLocation(locationRef)
|
|
if err != nil {
|
|
return clues.Wrap(err, "getting LocationIDer")
|
|
}
|
|
|
|
for uniqueLoc.elementCount() > 0 {
|
|
mapKey := uniqueLoc.ID().ShortRef()
|
|
|
|
name := uniqueLoc.lastElem()
|
|
if len(name) == 0 {
|
|
return clues.New("folder with no display name").
|
|
With("repo_ref", repoRef, "location_ref", uniqueLoc.InDetails())
|
|
}
|
|
|
|
shortRef := repoRef.ShortRef()
|
|
rr := repoRef.String()
|
|
|
|
// Get the parent of this entry to add as the LocationRef for the folder.
|
|
uniqueLoc.dir()
|
|
|
|
repoRef = repoRef.Dir()
|
|
parentRef := repoRef.ShortRef()
|
|
|
|
folder, ok := b.knownFolders[mapKey]
|
|
if !ok {
|
|
loc := uniqueLoc.InDetails().String()
|
|
|
|
folder = Entry{
|
|
RepoRef: rr,
|
|
ShortRef: shortRef,
|
|
ParentRef: parentRef,
|
|
LocationRef: loc,
|
|
ItemInfo: ItemInfo{
|
|
Folder: &FolderInfo{
|
|
ItemType: FolderItem,
|
|
// TODO(ashmrtn): Use the item type returned by the entry once
|
|
// SharePoint properly sets it.
|
|
DisplayName: name,
|
|
},
|
|
},
|
|
}
|
|
|
|
if err := entry.updateFolder(folder.Folder); err != nil {
|
|
return clues.Wrap(err, "adding folder").
|
|
With("parent_repo_ref", repoRef, "location_ref", loc)
|
|
}
|
|
}
|
|
|
|
folder.Folder.Size += entry.size()
|
|
folder.Updated = folder.Updated || entry.Updated
|
|
|
|
itemModified := entry.Modified()
|
|
if folder.Folder.Modified.Before(itemModified) {
|
|
folder.Folder.Modified = itemModified
|
|
}
|
|
|
|
// Always update the map because we're storing structs not pointers to
|
|
// structs.
|
|
b.knownFolders[mapKey] = folder
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (b *Builder) Details() *Details {
|
|
b.mu.Lock()
|
|
defer b.mu.Unlock()
|
|
|
|
ents := make([]Entry, len(b.d.Entries))
|
|
copy(ents, b.d.Entries)
|
|
|
|
// Write the cached folder entries to details
|
|
details := &Details{
|
|
DetailsModel{
|
|
Entries: append(ents, maps.Values(b.knownFolders)...),
|
|
},
|
|
}
|
|
|
|
return details
|
|
}
|