mirror of https://github.com/perkeep/perkeep.git
218 lines
6.9 KiB
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
|
|
}
|