perkeep/app/scanningcabinet/models.go

218 lines
6.9 KiB
Go

/*
Copyright 2017 The Perkeep Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"fmt"
"strings"
"time"
"perkeep.org/pkg/blob"
)
const (
// the format in which all dates are displayed and entered
dateformatYyyyMmDd = "2006-01-02"
)
// mediaObject represents the metadata associated with each individual uploaded scan.
// It is stored as a permanode with the "scanningcabinet:scan" camliNodeType value.
type mediaObject struct {
// permanode for this scan.
permanode blob.Ref
// contentRef is the image file blobRef.
// Stored as nodeattr.CamliContent.
contentRef blob.Ref
// Creation is the time when this struct was originally created.
// Stored as nodeattr.DateCreated, which makes this field the default
// sorting criterion when searching for scans.
creation time.Time
// TODO(mpl): as with the ContentType, I've removed the filename, because it is
// already stored in the file schema blob, so it would be redundant to store it in
// the scan permanode. It is not needed anywhere for now, but I think it could be
// used as the "alt" field for the raw scan img (which the original app didn't seem
// to do).
// DocumentRef is the blobRef of the associated Document permanode.
// A Document has many MediaObjects. When newly uploaded,
// a MediaObject is not associated with a Document.
documentRef blob.Ref
}
// urlResize returns the URL that displays this struct at an unspecified size.
// The size must by subsequently specified by concatenating an integer to make a legal URL.
func (mo *mediaObject) urlResize() string {
return fmt.Sprintf("%s?resize=", mo.displayURL())
}
// thumbUrl returns the URL that displays this struct at a thumbnail size.
func (mo *mediaObject) thumbUrl() string {
return fmt.Sprintf("%s?resize=300", mo.displayURL())
}
// displayURL returns the URL that displays this struct at its original size
func (mo *mediaObject) displayURL() string {
return fmt.Sprintf("resource/%s", mo.permanode.String())
}
// MediaObjectVM stores the MediaObject data required by the view templates
type MediaObjectVM struct {
BlobRef blob.Ref
UrlResize string
ThumbUrl string
}
// MakeViewModel returns a new DocumentVM with the data from this struct
func (mo *mediaObject) MakeViewModel() MediaObjectVM {
return MediaObjectVM{
BlobRef: mo.permanode,
UrlResize: mo.urlResize(),
ThumbUrl: mo.thumbUrl(),
}
}
// MakeMediaObjectViewModels takes a slice of MediaObjects and returns a slice of
// the same number of MediaObjectVMs with the data converted.
func MakeMediaObjectViewModels(mediaObjects []mediaObject) []MediaObjectVM {
models := make([]MediaObjectVM, len(mediaObjects))
for i := 0; i < len(mediaObjects); i++ {
models[i] = mediaObjects[i].MakeViewModel()
}
return models
}
// Document is a structure that groups scans into a logical unit.
// A letter (Stored as a document) could have several pages
// (each is a MediaObject), for example.
// It is stored as a permanode with the "scanningcabinet:doc" camliNodeType value.
type document struct {
// permanode for this document.
permanode blob.Ref
// Pages are the blobRefs of each Media Object that contitute this Document.
// Each page is stored as camliPath:pageNumber = blobRef.
// The first pageNumber is zero.
pages []blob.Ref
// Creation is the date the Document struct was created
// Stored as nodeAttr.DateCreated.
creation time.Time
// Fields below are user-set, and hence optional.
// DocDate is the user-nominated date associated with this document. It can
// store any date the user likes but is intended to be when the document was
// received, or, perhaps, written or sent.
// Stored as nodeattr.StartDate.
docDate time.Time
// Title is the user-nominated title of the document.
// Stored as nodeattr.Title.
title string
// Tags is the slice of zero or more tags associated with the document by the user.
// Stored as tag.
tags separatedString
// PhysicalLocation is the user-nominated description of the location
// of the physical document of which the MediaObjects associated with this
// Document are scans.
// Stored as nodeAttr.LocationText.
physicalLocation string
// DueDate is the user-nominated date that the document is "due". The
// meaning of what "due" means in relation to each particular document
// is up to the user
// Stored as nodeAttr.PaymentDueDate.
dueDate time.Time
}
// displayURL returns the url that displays this struct
func (doc *document) displayURL() string {
return fmt.Sprintf("doc/%s", doc.permanode)
}
// SomeTitle returns this struct's title or, failing that, its tags -
// and even failing that, its IntID
func (doc *document) someTitle() string {
if doc.title != "" {
return doc.title
}
if doc.tags.isEmpty() {
return fmt.Sprintf("Doc Ref %s", doc.permanode)
}
return strings.Join(doc.tags, ",")
}
// DateYyyyMmDd formats this struct's DocDate according to the DateformatYyyyMmDd const
func (doc *document) dateYyyyMmDd() string {
return formatYyyyMmDd(doc.docDate)
}
// DateYyyyMmDd formats this struct's DueDate according to the DateformatYyyyMmDd const
func (doc *document) dueYyyyMmDd() string {
return formatYyyyMmDd(doc.dueDate)
}
// formatYyyyMmDd is a convenience function that formats a given Time according to
// the DateformatYyyyMmDd const
func formatYyyyMmDd(indate time.Time) string {
if indate.IsZero() {
return ""
}
return indate.Format(dateformatYyyyMmDd)
}
// DocumentVM stores the Document data required by the view templates
type DocumentVM struct {
BlobRef blob.Ref
Title string
SomeTitle string
DateYyyyMmDd string
DueYyyyMmDd string
DisplayUrl string
Tags separatedString
PhysicalLocation string
}
// MakeViewModel returns a new DocumentVM with the data from this struct
func (doc *document) MakeViewModel() DocumentVM {
return DocumentVM{
BlobRef: doc.permanode,
DisplayUrl: doc.displayURL(),
Title: doc.title,
SomeTitle: doc.someTitle(),
DateYyyyMmDd: doc.dateYyyyMmDd(),
DueYyyyMmDd: doc.dueYyyyMmDd(),
Tags: doc.tags,
PhysicalLocation: doc.physicalLocation,
}
}
// MakeDocumentViewModels takes a slice of Documents and returns a slice of
// the same number of DocumentVMs with the data converted.
func MakeDocumentViewModels(docs []*document) []DocumentVM {
models := make([]DocumentVM, len(docs))
for i := 0; i < len(docs); i++ {
models[i] = docs[i].MakeViewModel()
}
return models
}