Documentation ¶
Index ¶
- Constants
- Variables
- func BagName() string
- func CanCountFromView(query *Query, model interface{}) bool
- func ETag() string
- func FileIdentifier(objIdentifier string) string
- func FiltersFor(typeName string) []string
- func GenericFileCreateBatch(files []*GenericFile) error
- func GetCountFromView(query *Query, model interface{}) (int, error)
- func IdForEventIdentifier(identifier string) (int64, error)
- func IdForFileIdentifier(identifier string) (int64, error)
- func IdForInstIdentifier(identifier string) (int64, error)
- func IdForObjIdentifier(identifier string) (int64, error)
- func InstIDFor(resourceType string, resourceID int64) (id int64, err error)
- func IsNoRowError(err error) bool
- func ObjIdentifier() string
- func ObjectEventCount(intellectualObjectID int64) (int, error)
- func ObjectFileCount(objID int64, filter, state string) (int, error)
- func RandomFileBatch() (*IntellectualObject, []*GenericFile, error)
- func Title() string
- type Alert
- type AlertView
- type AlertsPremisEvents
- type AlertsUsers
- type AlertsWorkItems
- type BaseModel
- type BillingStats
- type Checksum
- type ChecksumView
- type DeletionRequest
- func CreateDeletionRequest(objects []*IntellectualObject, files []*GenericFile) (*DeletionRequest, error)
- func DeletionRequestByID(id int64) (*DeletionRequest, error)
- func DeletionRequestGet(query *Query) (*DeletionRequest, error)
- func DeletionRequestSelect(query *Query) ([]*DeletionRequest, error)
- func NewDeletionRequest() (*DeletionRequest, error)
- func (request *DeletionRequest) AddFile(gf *GenericFile)
- func (request *DeletionRequest) AddObject(obj *IntellectualObject)
- func (request *DeletionRequest) Cancel(user *User)
- func (request *DeletionRequest) Confirm(user *User)
- func (request *DeletionRequest) FirstFile() *GenericFile
- func (request *DeletionRequest) FirstObject() *IntellectualObject
- func (request *DeletionRequest) Save() error
- func (r *DeletionRequest) ToMin() *DeletionRequestMin
- func (request *DeletionRequest) Validate() *common.ValidationError
- type DeletionRequestMin
- type DeletionRequestView
- type DeletionRequestsGenericFiles
- type DeletionRequestsIntellectualObjects
- type DepositFormatStats
- type DepositStats
- type FilterCollection
- func (fc *FilterCollection) Add(key string, values []string) (*ParamFilter, error)
- func (fc *FilterCollection) AddOrderBy(colAndDir string)
- func (fc *FilterCollection) HasExplicitSorting() bool
- func (fc *FilterCollection) ToQuery() (*Query, error)
- func (fc *FilterCollection) ValueOf(filterName string) string
- func (fc *FilterCollection) ValuesOf(filterName string) []string
- type GenericFile
- func GenericFileByID(id int64) (*GenericFile, error)
- func GenericFileByIdentifier(identifier string) (*GenericFile, error)
- func GenericFileGet(query *Query) (*GenericFile, error)
- func GenericFileSelect(query *Query) ([]*GenericFile, error)
- func ObjectFiles(objID int64, filter, state string, offset, limit int) ([]*GenericFile, error)
- func RandomGenericFile(objID int64, objIdentifier string) *GenericFile
- func (gf *GenericFile) ActiveDeletionWorkItem() (*WorkItem, error)
- func (gf *GenericFile) AssertDeletionPreconditions() error
- func (gf *GenericFile) Delete() error
- func (gf *GenericFile) DeletionRequest(workItemID int64) (*DeletionRequestView, error)
- func (gf *GenericFile) IsGlacierOnly() bool
- func (gf *GenericFile) LastDeletionEvent() (*PremisEvent, error)
- func (gf *GenericFile) LastIngestEvent() (*PremisEvent, error)
- func (gf *GenericFile) NewDeletionEvent() (*PremisEvent, error)
- func (gf *GenericFile) Save() error
- func (gf *GenericFile) Validate() *common.ValidationError
- func (gf *GenericFile) ValidateChanges(updatedFile *GenericFile) error
- type GenericFileCount
- type GenericFileView
- type Institution
- func (inst *Institution) Delete() error
- func (i *Institution) DisplayType() string
- func (inst *Institution) DueForSpotRestore() (bool, error)
- func (inst *Institution) GetAssociateMembers() ([]*Institution, error)
- func (inst *Institution) HasSubAccounts() (bool, error)
- func (inst *Institution) Save() error
- func (inst *Institution) Undelete() error
- func (inst *Institution) Validate() *common.ValidationError
- type InstitutionView
- type IntellectualObject
- func CreateObjectWithRelations() (*IntellectualObject, error)
- func GetTestObject() *IntellectualObject
- func IntellectualObjectByID(id int64) (*IntellectualObject, error)
- func IntellectualObjectByIdentifier(identifier string) (*IntellectualObject, error)
- func IntellectualObjectGet(query *Query) (*IntellectualObject, error)
- func IntellectualObjectSelect(query *Query) ([]*IntellectualObject, error)
- func RandomObject() *IntellectualObject
- func (obj *IntellectualObject) ActiveDeletionWorkItem() (*WorkItem, error)
- func (obj *IntellectualObject) AssertDeletionPreconditions() error
- func (obj *IntellectualObject) Delete() error
- func (obj *IntellectualObject) DeletionRequest(workItemID int64) (*DeletionRequestView, error)
- func (obj *IntellectualObject) HasActiveFiles() (bool, error)
- func (obj *IntellectualObject) IsGlacierOnly() bool
- func (obj *IntellectualObject) LastDeletionEvent() (*PremisEvent, error)
- func (obj *IntellectualObject) LastIngestEvent() (*PremisEvent, error)
- func (obj *IntellectualObject) NewDeletionEvent() (*PremisEvent, error)
- func (obj *IntellectualObject) Save() error
- func (obj *IntellectualObject) Validate() *common.ValidationError
- func (obj *IntellectualObject) ValidateChanges(updatedObj *IntellectualObject) error
- type IntellectualObjectCount
- type IntellectualObjectView
- func IntellectualObjectViewByID(id int64) (*IntellectualObjectView, error)
- func IntellectualObjectViewByIdentifier(identifier string) (*IntellectualObjectView, error)
- func IntellectualObjectViewGet(query *Query) (*IntellectualObjectView, error)
- func IntellectualObjectViewSelect(query *Query) ([]*IntellectualObjectView, error)
- func SmallestObjectNotRestoredInXDays(institutionID, minSize int64, days int) (*IntellectualObjectView, error)
- type InternalMetadata
- type Model
- type ParamFilter
- type PremisEvent
- type PremisEventCount
- type PremisEventView
- type Query
- func (q *Query) And(cols, ops []string, vals []interface{}) *Query
- func (q *Query) BetweenExclusive(col string, low, high interface{}) *Query
- func (q *Query) BetweenInclusive(col string, low, high interface{}) *Query
- func (q *Query) Columns(cols ...string) *Query
- func (q *Query) CopyForCount() *Query
- func (q *Query) Count(model interface{}) (int, error)
- func (q *Query) GetColumns() []string
- func (q *Query) GetColumnsInWhereClause() []string
- func (q *Query) GetLimit() int
- func (q *Query) GetOffset() int
- func (q *Query) GetOrderBy() []string
- func (q *Query) GetRelations() []string
- func (q *Query) IsNotNull(col string) *Query
- func (q *Query) IsNull(col string) *Query
- func (q *Query) Limit(limit int) *Query
- func (q *Query) MakePlaceholders(start, count int) string
- func (q *Query) Offset(offset int) *Query
- func (q *Query) Or(cols, ops []string, vals []interface{}) *Query
- func (q *Query) OrderBy(column, direction string) *Query
- func (q *Query) Params() []interface{}
- func (q *Query) Relations(relations ...string) *Query
- func (q *Query) Select(structOrSlice interface{}) error
- func (q *Query) Where(col, op string, val interface{}) *Query
- func (q *Query) WhereClause() string
- func (q *Query) WhereIn(col string, vals ...interface{}) *Query
- func (q *Query) WhereNotIn(col string, vals ...interface{}) *Query
- type SchemaMigration
- type SortParam
- type StorageOption
- type StorageRecord
- type TimestampModel
- type User
- func (user *User) ClearOTPSecret() error
- func (user *User) CountryCodeAndPhone() (int32, string, error)
- func (user *User) CreateOTPToken() (string, error)
- func (user *User) Delete() error
- func (user *User) HasPermission(action constants.Permission, institutionID int64) bool
- func (user *User) IsAdmin() bool
- func (user *User) IsAuthyOneTouchUser() bool
- func (user *User) IsSMSUser() bool
- func (user *User) IsTwoFactorUser() bool
- func (user *User) Save() error
- func (user *User) SignOut() error
- func (user *User) ToMin() *UserMin
- func (user *User) TwoFactorMethod() string
- func (user *User) Undelete() error
- func (user *User) Validate() *common.ValidationError
- type UserMin
- type UserView
- type WorkItem
- func LastSuccessfulIngest(objID int64) (*WorkItem, error)
- func NewDeletionItem(obj *IntellectualObject, gf *GenericFile, requestedBy, approvedBy *User) (*WorkItem, error)
- func NewItemFromLastSuccessfulIngest(objID int64) (*WorkItem, error)
- func NewRestorationItem(obj *IntellectualObject, gf *GenericFile, user *User) (*WorkItem, error)
- func RandomWorkItem(name, action string, objID, gfID int64) *WorkItem
- func WorkItemByID(id int64) (*WorkItem, error)
- func WorkItemGet(query *Query) (*WorkItem, error)
- func WorkItemSelect(query *Query) ([]*WorkItem, error)
- func WorkItemsPendingForFile(fileID int64) ([]*WorkItem, error)
- func WorkItemsPendingForObject(instID int64, bagName string) ([]*WorkItem, error)
- func (item *WorkItem) AlertOnSuccessfulSpotTest() *Alert
- func (item *WorkItem) GetSpotTestDetails() (*Institution, *IntellectualObject, error)
- func (item *WorkItem) HasCompleted() bool
- func (item *WorkItem) Save() error
- func (item *WorkItem) SetForRequeue(stage string) error
- func (item *WorkItem) Validate() *common.ValidationError
- func (item *WorkItem) ValidateChanges(updatedItem *WorkItem) error
- type WorkItemCount
- type WorkItemView
- func (item *WorkItemView) FindIngestedObject() (*IntellectualObject, error)
- func (item *WorkItemView) GetID() int64
- func (item *WorkItemView) GetObjIdentifier() string
- func (item *WorkItemView) HasCompleted() bool
- func (item *WorkItemView) IngestObjectLinkIsMissing() bool
- func (item *WorkItemView) Validate() *common.ValidationError
Constants ¶
const ( ErrAlertInstitutionID = "InstitutionID is required." ErrAlertType = "Alert type is missing or invalid." ErrAlertContent = "Alert content cannot be empty." )
const ( ErrDeletionInstitutionID = "Deletion request requires institution id." ErrDeletionRequesterID = "Deletion request requires requester id." ErrDeletionWrongInst = "Deletion request user belongs to wrong institution." ErrDeletionWrongRole = "Deletion confirmer/canceller must be institutional admin." ErrDeletionUserNotFound = "User does not exist." ErrDeletionUserInactive = "User has been deactivated." ErrTokenNotEncrypted = "Token must be encrypted." ErrDeletionIllegalObject = "User cannot delete files or objects belonging to other institutions." ErrDeletionBadAdmin = "Admin cannot confirm deletion they requested. This must be approved by a second admin." ErrDeletionBadQuery = "Cannot get admin list for this institution." )
const ( ErrInstName = "Name must contain 5-100 characters." ErrInstIdentifier = "Identifier must be a domain name." ErrInstState = "State must be 'A' or 'D'." ErrInstType = "Please choose an institution type." ErrInstReceiving = "Receiving bucket name is not valid." ErrInstRestore = "Restoration bucket name is not valid." ErrInstMemberID = "Please choose a parent institution." )
const ( TypeInsert xactType = iota TypeUpdate )
const ( ErrStorageOptionProvider = "Provider is required." ErrStorageOptionService = "Service is required." ErrStorageOptionRegion = "Region is required." ErrStorageOptionName = "Name is required." ErrStorageOptionCost = "Cost is required." ErrStorageOptionComment = "Comment is required." )
const ( ErrUserName = "Name must contain at least 2 characters." ErrUserEmail = "Email address is required." ErrUserPhone = "Please enter a phone number in format +2125551212." ErrUser2Factor = "Please choose yes or no." ErrUserGracePeriod = "Enter a date specifying when this user must enable two-factor authentication." ErrUserInst = "Please choose an institution." ErrUserRole = "Please choose a role for this user." ErrUserInstNotFound = "Internal error: cannot find institution." ErrUserInvalidAdmin = "Sys Admin role is not valid for this institution." ErrUserPwdMissing = "Encrypted password is missing." ErrUserPwdIncorrect = "Incorrect Password." )
const ( ErrItemName = "Name is required." ErrItemETag = "ETag is required (32-40 bytes)." ErrItemBagDate = "BagDate is required." ErrItemBucket = "Bucket is required." ErrItemUser = "User must be a valid email address." ErrItemInstID = "InstitutionID is required." ErrItemDateProcessed = "DateProcessed is required." ErrItemNote = "Note cannot be empty." ErrItemAction = "Action is missing or invalid." ErrItemStage = "Stage is missing or invalid." ErrItemStatus = "Status is missing or invalid." ErrItemOutcome = "Outcome cannot be empty." )
Variables ¶
var AlertFilters = []string{
"created_at__gteq",
"created_at__lteq",
"institution_id",
"type",
"user_id",
}
var ChecksumFilters = []string{
"algorithm",
"datetime__gteq",
"datetime__lteq",
"digest",
"generic_file_id",
"generic_file_identifier",
"institution_id",
"intellectual_object_id",
"state",
}
var DeletionRequestFilters = []string{
"institution_id",
"requested_at__gteq",
"requested_at__lteq",
"stage",
"status",
}
var DepositStatsFilters = []string{
"chart_metric",
"end_date",
"institution_id",
"report_type",
"start_date",
"storage_option",
}
Note: chart_metric and report_type are ignored by backend. Used only in front-end.
var GenericFileCountFilters = []string{
"institution_id",
"state",
}
var GenericFileFilters = []string{
"identifier",
"uuid",
"intellectual_object_id",
"institution_id",
"state",
"storage_option",
"storage_option__in",
"size__gteq",
"size__lteq",
"created_at__gteq",
"created_at__lteq",
"updated_at__gteq",
"updated_at__lteq",
"last_fixity_check__gteq",
"last_fixity_check__lteq",
}
var InstitutionFilters = []string{
"name__contains",
"type",
}
var IntellectualObjectCountFilters = []string{
"institution_id",
"state",
}
var IntellectualObjectFilters = []string{
"access",
"alt_identifier",
"alt_identifier__starts_with",
"bag_group_identifier",
"bag_group_identifier__starts_with",
"bag_name",
"bagit_profile_identifier",
"created_at__lteq",
"created_at__gteq",
"etag",
"file_count__gteq",
"file_count__lteq",
"identifier",
"institution_id",
"institution_parent_id",
"internal_sender_description",
"internal_sender_identifier",
"size__gteq",
"size__lteq",
"source_organization",
"state",
"storage_option",
"updated_at__gteq",
"updated_at__lteq",
}
IntellectualObjectFilters describes the allowed filters for searching IntellectualObjects. Some of these are commented out because, while they are supported in Pharo's v2 member API, we want to phase them out. "Contains" queries, in particular, which use SQL "like" on the backend, cause performance problems.
var PremisEventCountFilters = []string{
"institution_id",
"event_type",
"outcome",
}
var PremisEventFilters = []string{
"date_time__gteq",
"date_time__lteq",
"event_type",
"generic_file_id",
"generic_file_id__is_null",
"generic_file_identifier",
"identifier",
"institution_id",
"intellectual_object_id",
"intellectual_object_identifier",
"outcome",
}
var QueryOp = map[string]string{
"eq": "=",
"ne": "!=",
"gt": ">",
"gteq": ">=",
"lt": "<",
"lteq": "<=",
"starts_with": "ILIKE",
"contains": "ILIKE",
"in": "IN",
"not_in": "NOT IN",
"is_null": "IS NULL",
"not_null": "IS NOT NULL",
}
var StorageRecordFilters = []string{
"generic_file_id",
}
var UserFilters = []string{
"deactivated_at__is_null",
"deactivated_at__is_not_null",
"email__contains",
"institution_id",
"name__contains",
"role",
}
var WorkItemCountFilters = []string{
"institution_id",
"action",
}
var WorkItemFilters = []string{
"action",
"action__in",
"alt_identifier",
"bag_date__gteq",
"bag_date__lteq",
"bag_group_identifier",
"bagit_profile_identifier",
"bucket",
"date_processed__gteq",
"date_processed__lteq",
"etag",
"generic_file_id",
"generic_file_id__is_null",
"generic_file_identifier",
"institution_id",
"intellectual_object_id",
"intellectual_object_id__is_null",
"name",
"needs_admin_review",
"node__is_null",
"node__not_null",
"object_identifier",
"queued_at__is_null",
"queued_at__not_null",
"retry",
"size__gteq",
"size__lteq",
"stage",
"stage__in",
"status",
"status__in",
"storage_option",
"user",
}
Functions ¶
func CanCountFromView ¶
func FileIdentifier ¶
func FiltersFor ¶
func GenericFileCreateBatch ¶
func GenericFileCreateBatch(files []*GenericFile) error
GenericFileCreateBatch creates a batch of GenericFiles and their dependent records (PremisEvents, Checksums, and StorageRecords) in a single transaction. This transaction's single commit is much more efficient than doing one commit per insert.
This is used heavily during ingest.
func GetCountFromView ¶
GetCountFromView returns a snapshotted count from a materialized view. We do this for some queries that are known to return very large counts, which take a long time in postgres.
Ideally, this should return int64, in line with our general practice of using int64. However, it has to be compatible with the pg library's built-in Count() function, which returns int.
func IdForEventIdentifier ¶
IdForEventIdentifier returns the ID of the PremisEvent having the specified identifier. These identifiers are UUID strings.
func IdForFileIdentifier ¶
IdForFileIdentifier returns the ID of the GenericFile having the specified identifier.
func IdForInstIdentifier ¶
IdForInstIdentifier returns the id of the insitution with the given identifier, or an error if no matching record exists.
func IdForObjIdentifier ¶
IdForFileIdentifier returns the ID of the IntellectualObject having the specified identifier.
func IsNoRowError ¶
IsNoRowError returns true if err is pg.ErrNoRows. For some reason, err doesn't compare correctly with pg.ErrNoRows, and errors.Is() doesn't work either. Probably because pg.ErrNoRows is an alias of an error in the pg/internal package, which we cannot access.
func ObjIdentifier ¶
func ObjIdentifier() string
func ObjectEventCount ¶
ObjectEventCount returns the number of object-level PremisEvents for the specified IntellectualObject. Note that queries on the premis_events table can be potentially quite expensive, since the table has well over 100M rows.
Object-level events include ingest, identifier assignment, access assignment and others. They exclude all events related to specific files (such as fixity check, etc.).
func ObjectFileCount ¶
ObjectFileCount returns the number of active files with the specified Intellectial Object ID.
func RandomFileBatch ¶
func RandomFileBatch() (*IntellectualObject, []*GenericFile, error)
RandFileBatch returns a slice of 20 GenericFiles, each with 4 events, checksums, and storage records. Note that this also creates the parent object in the database. You may want to reset the DB after calling this.
Types ¶
type Alert ¶
type Alert struct { BaseModel InstitutionID int64 `json:"institution_id"` Type string `json:"type"` Subject string `json:"subject"` Content string `json:"content"` DeletionRequestID int64 `json:"deletion_request_id"` CreatedAt time.Time `json:"created_at"` DeletionRequest *DeletionRequest `json:"-" pg:"rel:has-one"` PremisEvents []*PremisEvent `json:"premis_events" pg:"many2many:alerts_premis_events"` Users []*User `json:"users" pg:"many2many:alerts_users"` WorkItems []*WorkItem `json:"work_items" pg:"many2many:alerts_work_items"` }
func AlertByID ¶
AlertByID returns the alert with the specified id. Returns pg.ErrNoRows if there is no match.
func AlertSelect ¶
AlertSelect returns all alerts matching the query.
func CreateAlert ¶
func CreateAlert(alert *Alert, templateName string, alertData map[string]interface{}) (*Alert, error)
CreateAlert adds customized text to the alert and saves it in the database. Param templateName is the name of the text template used to construct the alert message. Param alertData is the custom data to put into the template.
This returns the alert with a non-zero ID (since it saves it) and an error if there's a problem with the template or the save.
func (*Alert) MarkAsRead ¶
MarkAsRead marks an alert as read if its current ReadAt date is null.
func (*Alert) MarkAsSent ¶
MarkAsSent marks an alert as sent.
func (*Alert) MarkAsUnread ¶
MarkAsUnread marks an alert as unread.
func (*Alert) Save ¶
Save saves this alert to the database. This will peform an insert if Alert.ID is zero. Otherwise, it updates. It also saves all of the many-to-many relations (PremisEvents, Users, and WorkItems), though note that on update it does not delete any of these relations. We don't have a use case for that yet, since alerts are generally created and never updated.
func (*Alert) Validate ¶
func (alert *Alert) Validate() *common.ValidationError
Validate validates the model. This is called automatically on insert and update.
type AlertView ¶
type AlertView struct { ID int64 `json:"id"` InstitutionID int64 `json:"institution_id"` InstitutionName string `json:"institution_name"` InstitutionIdentifier string `json:"institution_identifier"` Type string `json:"type"` Subject string `json:"subject"` Content string `json:"content"` DeletionRequestID int64 `json:"deletion_request_id"` CreatedAt time.Time `json:"created_at"` UserID int64 `json:"user_id"` UserName string `json:"user_name"` UserEmail string `json:"user_email"` SentAt time.Time `json:"sent_at"` ReadAt time.Time `json:"read_at"` // contains filtered or unexported fields }
func AlertViewForUser ¶
AlertViewForUser returns the alert with the specified ID for the specified recipient (user id). Returns pg.ErrNoRows if there is no match.
func AlertViewGet ¶
AlertViewGet returns the first alert matching the query.
func AlertViewSelect ¶
AlertViewSelect returns all alerts matching the query.
func (*AlertView) HasBeenRead ¶
type AlertsPremisEvents ¶
type AlertsUsers ¶
type AlertsWorkItems ¶
type BillingStats ¶
type BillingStats struct { InstitutionID int64 `json:"institution_id"` InstitutionName string `json:"institution_name"` EndDate time.Time `json:"end_date"` MonthAndYear string `json:"month_and_year"` StorageOption string `json:"storage_option"` TotalGB float64 `json:"total_gb"` TotalTB float64 `json:"total_tb"` Overage float64 `json:"overage"` }
func BillingStatsSelect ¶
type Checksum ¶
type Checksum struct { TimestampModel Algorithm string `json:"algorithm"` DateTime time.Time `json:"datetime" pg:"datetime"` Digest string `json:"digest"` GenericFileID int64 `json:"generic_file_id" pg:"generic_file_id"` GenericFile *GenericFile `json:"-" pg:"rel:has-one"` }
func ChecksumByID ¶
ChecksumByID returns the file with the specified id. Returns pg.ErrNoRows if there is no match.
func ChecksumGet ¶
ChecksumGet returns the first file matching the query.
func ChecksumSelect ¶
ChecksumSelect returns all files matching the query.
func RandomChecksum ¶
RandomChecksum returns a random checksum with the specified algorithm. Caller should set GenericFileID.
func (*Checksum) Save ¶
Save saves this file to the database. This will peform an insert if Checksum.ID is zero. Otherwise, it returns an error, since updating checksums is not allowed. Checksums should only ever change on re-ingest, when we get a new version of an existing file. In that case, we add a new checksum, so that we have records for all checksums that have existed over time.
func (*Checksum) Validate ¶
func (cs *Checksum) Validate() *common.ValidationError
type ChecksumView ¶
type ChecksumView struct { ID int64 `json:"id"` Algorithm string `json:"algorithm"` DateTime time.Time `json:"datetime" pg:"datetime"` Digest string `json:"digest"` State string `json:"state"` GenericFileIdentifier string `json:"generic_file_identifier"` GenericFileID int64 `json:"generic_file_id"` IntellectualObjectID int64 `json:"intellectual_object_id"` InstitutionID int64 `json:"institution_id"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` // contains filtered or unexported fields }
func ChecksumViewByID ¶
func ChecksumViewByID(id int64) (*ChecksumView, error)
ChecksumViewByID returns the file with the specified id. Returns pg.ErrNoRows if there is no match.
func ChecksumViewGet ¶
func ChecksumViewGet(query *Query) (*ChecksumView, error)
ChecksumViewGet returns the first file matching the query.
func ChecksumViewSelect ¶
func ChecksumViewSelect(query *Query) ([]*ChecksumView, error)
ChecksumViewSelect returns all files matching the query.
type DeletionRequest ¶
type DeletionRequest struct { BaseModel InstitutionID int64 `json:"institution_id"` RequestedByID int64 `json:"-"` RequestedAt time.Time `json:"requested_at"` ConfirmationToken string `json:"-" pg:"-"` EncryptedConfirmationToken string `json:"-"` ConfirmedByID int64 `json:"-"` ConfirmedAt time.Time `json:"confirmed_at"` CancelledByID int64 `json:"-"` CancelledAt time.Time `json:"cancelled_at"` RequestedBy *User `json:"requested_by" pg:"rel:has-one"` ConfirmedBy *User `json:"confirmed_by" pg:"rel:has-one"` CancelledBy *User `json:"cancelled_by" pg:"rel:has-one"` WorkItemID int64 `json:"work_item_id"` GenericFiles []*GenericFile `json:"generic_files" pg:"many2many:deletion_requests_generic_files"` IntellectualObjects []*IntellectualObject `json:"intellectual_objects" pg:"many2many:deletion_requests_intellectual_objects"` WorkItem *WorkItem `json:"work_item" pg:"rel:has-one"` }
func CreateDeletionRequest ¶
func CreateDeletionRequest(objects []*IntellectualObject, files []*GenericFile) (*DeletionRequest, error)
func DeletionRequestByID ¶
func DeletionRequestByID(id int64) (*DeletionRequest, error)
DeletionRequestByID returns the institution with the specified id. Returns pg.ErrNoRows if there is no match.
func DeletionRequestGet ¶
func DeletionRequestGet(query *Query) (*DeletionRequest, error)
DeletionRequestGet returns the first deletion request matching the query.
func DeletionRequestSelect ¶
func DeletionRequestSelect(query *Query) ([]*DeletionRequest, error)
DeletionRequestSelect returns all deletion requests matching the query.
func NewDeletionRequest ¶
func NewDeletionRequest() (*DeletionRequest, error)
func (*DeletionRequest) AddFile ¶
func (request *DeletionRequest) AddFile(gf *GenericFile)
func (*DeletionRequest) AddObject ¶
func (request *DeletionRequest) AddObject(obj *IntellectualObject)
func (*DeletionRequest) Cancel ¶
func (request *DeletionRequest) Cancel(user *User)
Cancel cancels this DeletionRequest. It's up to the caller to save this request after cancelling it.
func (*DeletionRequest) Confirm ¶
func (request *DeletionRequest) Confirm(user *User)
Confirm marks this DeletionRequest as confirmed. It's up to the caller to save the request and create an appropriate WorkItem.
func (*DeletionRequest) FirstFile ¶
func (request *DeletionRequest) FirstFile() *GenericFile
FirstFile returns the first GenericFile associated with this deletion request. Use this for simple, single-file deletions.
func (*DeletionRequest) FirstObject ¶
func (request *DeletionRequest) FirstObject() *IntellectualObject
FirstObject returns the first IntellectualObject associated with this deletion request. Use this for simple, single-object deletions.
func (*DeletionRequest) Save ¶
func (request *DeletionRequest) Save() error
Save saves this requestitution to the database. This will peform an insert if DeletionRequest.ID is zero. Otherwise, it updates.
func (*DeletionRequest) ToMin ¶
func (r *DeletionRequest) ToMin() *DeletionRequestMin
ToMin returns DeletionRequestMin object suitable for serialization in the member API.
func (*DeletionRequest) Validate ¶
func (request *DeletionRequest) Validate() *common.ValidationError
Validation enforces business rules, including who can request and confirm deletions. Although our general security middleware should prevent any of these problems from ever occurring, we want to double check everything here because we're a preservation archive and deletion is a destructive action. We must be sure deletion is a deliberate act initiated and confirmed by authorized individuals.
type DeletionRequestMin ¶
type DeletionRequestMin struct { ID int64 `json:"id"` InstitutionID int64 `json:"institution_id"` RequestedAt time.Time `json:"requested_at"` ConfirmedAt time.Time `json:"confirmed_at"` CancelledAt time.Time `json:"cancelled_at"` RequestedBy *UserMin `json:"requested_by"` ConfirmedBy *UserMin `json:"confirmed_by"` CancelledBy *UserMin `json:"cancelled_by"` GenericFiles []*GenericFile `json:"generic_files"` IntellectualObjects []*IntellectualObject `json:"intellectual_objects"` WorkItem *WorkItem `json:"work_item"` }
DeletionRequestMin includes the subset of DeletionRequest info that we want to expose through the member API.
type DeletionRequestView ¶
type DeletionRequestView struct { ID int64 `json:"id"` InstitutionID int64 `json:"institution_id"` InstitutionName string `json:"institution_name"` InstitutionIdentifier string `json:"institution_identifier"` RequestedByID int64 `json:"requested_by_id"` RequestedByName string `json:"requested_by_name"` RequestedByEmail string `json:"requested_by_email"` RequestedAt time.Time `json:"requested_at"` ConfirmedByID int64 `json:"confirmed_by_id"` ConfirmedByName string `json:"confirmed_by_name"` ConfirmedByEmail string `json:"confirmed_by_email"` ConfirmedAt time.Time `json:"confirmed_at"` CancelledByID int64 `json:"cancelled_by_id"` CancelledByName string `json:"cancelled_by_name"` CancelledByEmail string `json:"cancelled_by_email"` CancelledAt time.Time `json:"cancelled_at"` FileCount int64 `json:"file_count"` ObjectCount int64 `json:"object_count"` WorkItemID int64 `json:"work_item_id"` Stage string `json:"stage"` Status string `json:"status"` DateProcessed time.Time `json:"date_processed"` Size int64 `json:"size"` Note string `json:"note"` // contains filtered or unexported fields }
DeletionRequestsView contains a flattened view of deletion requests suitable for the index page.
func DeletionRequestViewByID ¶
func DeletionRequestViewByID(id int64) (*DeletionRequestView, error)
DeletionRequestViewByID returns the DeletionRequestView record with the specified id. Returns pg.ErrNoRows if there is no match.
func DeletionRequestViewGet ¶
func DeletionRequestViewGet(query *Query) (*DeletionRequestView, error)
DeletionRequestViewGet returns the first user view record matching the query.
func DeletionRequestViewSelect ¶
func DeletionRequestViewSelect(query *Query) ([]*DeletionRequestView, error)
DeletionRequestViewSelect returns all DeletionRequestView records matching the query.
func (*DeletionRequestView) DisplayStatus ¶
func (request *DeletionRequestView) DisplayStatus() string
DisplayStatus returns a string saying whether this deletion request has been cancelled, is in progress, or complete, or whatever.
type DepositFormatStats ¶
type DepositFormatStats struct { FileFormat string `json:"file_format"` FileCount int64 `json:"file_count"` TotalBytes int64 `json:"total_bytes"` TotalGB float64 `json:"total_gb" pg:"total_gb"` TotalTB float64 `json:"total_tb" pg:"total_tb"` }
func DepositFormatStatsSelect ¶
func DepositFormatStatsSelect(institutionID, intellectualObjectID int64) ([]*DepositFormatStats, error)
DepositFormatStatsSelect returns summary stats on the files belonging to the specified institution and/or object. Specify object ID for object status, Institution ID for institution status.
Note that stats come back in different order on MacOs vs Linux. https://dba.stackexchange.com/questions/106964/why-is-my-postgresql-order-by-case-insensitive
func StatsByFormat ¶
func StatsByFormat(stats []*DepositFormatStats, format string) *DepositFormatStats
StatsByFormat returns the stats for the specified format, or nil if not found.
type DepositStats ¶
type DepositStats struct { InstitutionID int64 `json:"institution_id"` MemberInstitutionID int64 `json:"member_institution_id"` InstitutionName string `json:"institution_name"` StorageOption string `json:"storage_option"` ObjectCount int64 `json:"object_count"` FileCount int64 `json:"file_count"` TotalBytes int64 `json:"total_bytes"` TotalGB float64 `json:"total_gb" pg:"total_gb"` TotalTB float64 `json:"total_tb" pg:"total_tb"` CostGBPerMonth float64 `json:"cost_gb_per_month" pg:"cost_gb_per_month"` MonthlyCost float64 `json:"monthly_cost"` EndDate time.Time `json:"end_date"` PrimarySort string `json:"-"` SecondarySort string `json:"-"` }
DepositStats contains info about member deposits and the costs of those deposits. This struct does not implement the usual pgmodel interface, nor does it map to a single underlying table or view. This struct merely represents to the output of a reporting query.
Note that we store CostGBPerMonth and MonthlyCost in the table rather than calculating them because cost per GB per month may change over time, and we want to capture the actual historical cost for each month.
func DepositStatsOverTime ¶
func DepositStatsSelect ¶
func DepositStatsSelect(institutionID int64, storageOption string, endDate time.Time) ([]*DepositStats, error)
DepositStatsSelect returns info about materials a depositor updated in our system before a given date. This breaks down deposits by storage option and institution. To report on all institutions, use zero for institutionID. To report on all storage options, pass an empty string for storageOption.
type FilterCollection ¶
type FilterCollection struct {
// contains filtered or unexported fields
}
FilterCollection converts query string params such as name__eq=Homer to a pgmodels.Query object that allows us to build a SQL where clause as we go.
func NewFilterCollection ¶
func NewFilterCollection() *FilterCollection
NewFilterCollection returns a ParamFileters object.
func (*FilterCollection) Add ¶
func (fc *FilterCollection) Add(key string, values []string) (*ParamFilter, error)
Add adds an item to the filter collection. Param key is a filter key from the query string. Param values are the values associated with that key. For example:
Key: name__in Values: ["Bart", "Lisa", "Maggie"]
func (*FilterCollection) AddOrderBy ¶
func (fc *FilterCollection) AddOrderBy(colAndDir string)
AddOrderBy adds sort columns to the filters. Param colAndDir should be in format "column_name__dir", where dir is "asc" or "desc". If dir is omitted, it defaults to "asc."
Examples: "created_at__desc", "id__asc".
func (*FilterCollection) HasExplicitSorting ¶
func (fc *FilterCollection) HasExplicitSorting() bool
HasExplicitSorting returns true if this object includes explicit sort params that will show up as an "order by" clause in the SQL query.
func (*FilterCollection) ToQuery ¶
func (fc *FilterCollection) ToQuery() (*Query, error)
ToQuery returns a query object based on the keys and values passed in. The Query's WhereClause() will return the where conditions for the filters passed in through Add(), and the Query's Params() method will return the params. Conditions and params come back in the order they were added.
func (*FilterCollection) ValueOf ¶
func (fc *FilterCollection) ValueOf(filterName string) string
ValueOf returns the value of the filter with the specified name. Returns an empty string if the specified filter is missing or has no value.
func (*FilterCollection) ValuesOf ¶
func (fc *FilterCollection) ValuesOf(filterName string) []string
ValuesOf returns all selected values for the specified filter.
type GenericFile ¶
type GenericFile struct { TimestampModel FileFormat string `json:"file_format"` Size int64 `json:"size"` Identifier string `json:"identifier"` IntellectualObjectID int64 `json:"intellectual_object_id"` State string `json:"state"` LastFixityCheck time.Time `json:"last_fixity_check"` InstitutionID int64 `json:"institution_id"` StorageOption string `json:"storage_option"` UUID string `json:"uuid" pg:"uuid"` Institution *Institution `json:"-" pg:"rel:has-one"` IntellectualObject *IntellectualObject `json:"-" pg:"rel:has-one"` PremisEvents []*PremisEvent `json:"premis_events" pg:"rel:has-many"` Checksums []*Checksum `json:"checksums" pg:"rel:has-many"` StorageRecords []*StorageRecord `json:"storage_records" pg:"rel:has-many"` }
func GenericFileByID ¶
func GenericFileByID(id int64) (*GenericFile, error)
GenericFileByID returns the file with the specified id. Returns pg.ErrNoRows if there is no match.
func GenericFileByIdentifier ¶
func GenericFileByIdentifier(identifier string) (*GenericFile, error)
GenericFileByIdentifier returns the file with the specified identifier. Returns pg.ErrNoRows if there is no match.
func GenericFileGet ¶
func GenericFileGet(query *Query) (*GenericFile, error)
GenericFileGet returns the first file matching the query.
func GenericFileSelect ¶
func GenericFileSelect(query *Query) ([]*GenericFile, error)
GenericFileSelect returns all files matching the query. Note that this returns related objects as well, including PremisEvents, Checksums, and StorageRecords.
func ObjectFiles ¶
func ObjectFiles(objID int64, filter, state string, offset, limit int) ([]*GenericFile, error)
Object files returns files belonging to an intellectual object. This function is used to filter files on the IntellectualObjectShow page. objID is the id of the object. filter is an optional file identifier or checksum. offset and limit are for paging. state is "A" for active (default) or "D" for deleted.
func RandomGenericFile ¶
func RandomGenericFile(objID int64, objIdentifier string) *GenericFile
RandomGenericFile returns a random generic file with the specified obj identifier prefix. State will be active.
func (*GenericFile) ActiveDeletionWorkItem ¶
func (gf *GenericFile) ActiveDeletionWorkItem() (*WorkItem, error)
ActiveDeletionWorkItem returns the in-progress WorkItem for this file's deletion. The WorkItem may be for the deletion of this specific file, or of its parent object.
func (*GenericFile) AssertDeletionPreconditions ¶
func (gf *GenericFile) AssertDeletionPreconditions() error
func (*GenericFile) Delete ¶
func (gf *GenericFile) Delete() error
Delete soft-deletes this file by setting State to 'D' and the UpdatedAt timestamp to now. You can undo this with Undelete. It also creates a deletion PremisEvent. You can't get rid of that.
It is legitimate for a depositor to delete a file, then re-upload it later, particularly if they want to change the storage option. In that case, the file's state would be set back to "A" after the new ingest, and the old deletion event would remain to show that an earlier version of the file was once deleted.
We would know the new file is active because state = "A" and it would have an ingest event dated after the last deletion event.
func (*GenericFile) DeletionRequest ¶
func (gf *GenericFile) DeletionRequest(workItemID int64) (*DeletionRequestView, error)
func (*GenericFile) IsGlacierOnly ¶
func (gf *GenericFile) IsGlacierOnly() bool
IsGlacierOnly returns true if this file is stored only in Glacier.
func (*GenericFile) LastDeletionEvent ¶
func (gf *GenericFile) LastDeletionEvent() (*PremisEvent, error)
LastDeleationEvent returns the latest deletion event for this file, which may be nil.
func (*GenericFile) LastIngestEvent ¶
func (gf *GenericFile) LastIngestEvent() (*PremisEvent, error)
LastIngestEvent returns the latest ingest event for this file. This should never be nil.
func (*GenericFile) NewDeletionEvent ¶
func (gf *GenericFile) NewDeletionEvent() (*PremisEvent, error)
func (*GenericFile) Save ¶
func (gf *GenericFile) Save() error
Save saves this file to the database. This will peform an insert if GenericFile.ID is zero. Otherwise, it updates.
Note that the insert/update also saves all associated records (checksums, storage records, and premis events).
func (*GenericFile) Validate ¶
func (gf *GenericFile) Validate() *common.ValidationError
func (*GenericFile) ValidateChanges ¶
func (gf *GenericFile) ValidateChanges(updatedFile *GenericFile) error
type GenericFileCount ¶
type GenericFileView ¶
type GenericFileView struct { ID int64 `json:"id" pg:"id"` FileFormat string `json:"file_format"` Size int64 `json:"size"` Identifier string `json:"identifier"` IntellectualObjectID int64 `json:"intellectual_object_id"` ObjectIdentifier string `json:"object_identifier"` Access string `json:"access"` State string `json:"state"` LastFixityCheck time.Time `json:"last_fixity_check"` InstitutionID int64 `json:"institution_id"` InstitutionName string `json:"institution_name"` InstitutionIdentifier string `json:"institution_identifier"` StorageOption string `json:"storage_option"` UUID string `json:"uuid" pg:"uuid"` Md5 string `json:"md5"` Sha1 string `json:"sha1"` Sha256 string `json:"sha256"` Sha512 string `json:"sha512"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` // This is a late hack. Needed for object restoration. // Note that there's no join the DB for this (and there shouldn't // be, because it would produce multiple records). The // GenericFilesController will hack in the storage records // only when specifically requested. StorageRecords []*StorageRecord `pg:"-" json:"storage_records,omitempty"` // contains filtered or unexported fields }
func GenericFileViewByID ¶
func GenericFileViewByID(id int64) (*GenericFileView, error)
GenericFileViewByID returns the GenericFileView record with the specified id. Returns pg.ErrNoRows if there is no match.
func GenericFileViewByIdentifier ¶
func GenericFileViewByIdentifier(identifier string) (*GenericFileView, error)
GenericFileViewByIdentifier returns the GenericFileView record with the specified email address. Returns pg.ErrNoRows if there is no match.
func GenericFileViewGet ¶
func GenericFileViewGet(query *Query) (*GenericFileView, error)
GenericFileViewGet returns the first user view record matching the query.
func GenericFileViewSelect ¶
func GenericFileViewSelect(query *Query) ([]*GenericFileView, error)
GenericFileViewSelect returns all GenericFileView records matching the query.
type Institution ¶
type Institution struct { TimestampModel Name string `json:"name"` Identifier string `json:"identifier"` State string `json:"state"` Type string `json:"type"` MemberInstitutionID int64 `json:"member_institution_id"` DeactivatedAt time.Time `json:"deactivated_at"` OTPEnabled bool `json:"otp_enabled" pg:",use_zero"` SpotRestoreFrequency int64 `json:"spot_restore_frequency" pg:",use_zero"` LastSpotRestoreWorkItemID int64 `json:"last_spot_restore_work_item_id"` ReceivingBucket string `json:"receiving_bucket"` RestoreBucket string `json:"restore_bucket"` }
func InstitutionByID ¶
func InstitutionByID(id int64) (*Institution, error)
InstitutionByID returns the institution with the specified id. Returns pg.ErrNoRows if there is no match.
func InstitutionByIdentifier ¶
func InstitutionByIdentifier(identifier string) (*Institution, error)
InstitutionByIdentifier returns the institution with the specified identifier. Returns pg.ErrNoRows if there is no match.
func InstitutionGet ¶
func InstitutionGet(query *Query) (*Institution, error)
InstitutionGet returns the first institution matching the query.
func InstitutionSelect ¶
func InstitutionSelect(query *Query) ([]*Institution, error)
InstitutionSelect returns all institutions matching the query.
func (*Institution) Delete ¶
func (inst *Institution) Delete() error
Delete soft-deletes this institution by setting State to 'D' and the DeletedAt timestamp to now. You can undo this with Undelete.
func (*Institution) DisplayType ¶
func (i *Institution) DisplayType() string
DisplayType returns either "Member" or "Associate" depending on the institution type. This is the type as we display it to users, not as we store it in the database. This method exists because we changed terminology in 2023.
"Subscription Institution", "Sub-Account", "Associate Member" and "Associate" all mean the same thing, but we're using "Associate" in the UI.
func (*Institution) DueForSpotRestore ¶
func (inst *Institution) DueForSpotRestore() (bool, error)
DueForSpotRestore returns true if this institution is due for a restoration spot test.
func (*Institution) GetAssociateMembers ¶
func (inst *Institution) GetAssociateMembers() ([]*Institution, error)
GetAssociateMembers returns a list of the associate members (aka sub-accounts) belonging to this subscribing member. This will return an empty list if the institution itself is an associate account, or if it has zero subscribing members.
func (*Institution) HasSubAccounts ¶
func (inst *Institution) HasSubAccounts() (bool, error)
HasSubAccounts returns true if this insitution has active sub-accounts, aka associate members.
func (*Institution) Save ¶
func (inst *Institution) Save() error
Save saves this institution to the database. This will peform an insert if Institution.ID is zero. Otherwise, it updates.
func (*Institution) Undelete ¶
func (inst *Institution) Undelete() error
Undelete reactivates this institution by setting State to 'A' and clearing the DeletedAt timestamp.
func (*Institution) Validate ¶
func (inst *Institution) Validate() *common.ValidationError
Validate validates the model. This is called automatically on insert and update.
type InstitutionView ¶
type InstitutionView struct { ID int64 `json:"id"` Name string `json:"name"` Identifier string `json:"identifier"` State string `json:"state"` Type string `json:"type"` DeactivatedAt time.Time `json:"deactivated_at"` OTPEnabled bool `json:"otp_enabled"` SpotRestoreFrequency int64 `json:"spot_restore_frequency" pg:",use_zero"` LastSpotRestoreWorkItemID int64 `json:"last_spot_restore_work_item_id"` ReceivingBucket string `json:"receiving_bucket"` RestoreBucket string `json:"restore_bucket"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` ParentId int64 `json:"parent_id"` ParentName string `json:"parent_name"` ParentIdentifier string `json:"parent_identifier"` ParentState string `json:"parent_state"` ParentDeactivatedAt time.Time `json:"parent_deactivated_at"` // contains filtered or unexported fields }
InstitutionView contains information about an institution and its parent (if it has one). This view simplifies both search and display for institution management.
func InstitutionViewByID ¶
func InstitutionViewByID(id int64) (*InstitutionView, error)
InstitutionViewByID returns the InstitutionView record with the specified id. Returns pg.ErrNoRows if there is no match.
func InstitutionViewByIdentifier ¶
func InstitutionViewByIdentifier(identifier string) (*InstitutionView, error)
InstitutionViewByIdentifier returns the InstitutionView record with the specified identifier (domain name). Returns pg.ErrNoRows if there is no match.
func InstitutionViewGet ¶
func InstitutionViewGet(query *Query) (*InstitutionView, error)
InstitutionViewGet returns the first user view record matching the query.
func InstitutionViewSelect ¶
func InstitutionViewSelect(query *Query) ([]*InstitutionView, error)
InstitutionViewSelect returns all InstitutionView records matching the query.
func (*InstitutionView) DisplayType ¶
func (i *InstitutionView) DisplayType() string
DisplayType returns either "Member" or "Associate" depending on the institution type. This is the type as we display it to users, not as we store it in the database. This method exists because we changed terminology in 2023.
"Subscription Institution", "Sub-Account", "Associate Member" and "Associate" all mean the same thing, but we're using "Associate" in the UI.
type IntellectualObject ¶
type IntellectualObject struct { TimestampModel Title string `json:"title"` Description string `json:"description"` Identifier string `json:"identifier"` AltIdentifier string `json:"alt_identifier"` Access string `json:"access"` BagName string `json:"bag_name"` InstitutionID int64 `json:"institution_id"` State string `json:"state"` ETag string `json:"etag" pg:"etag"` BagGroupIdentifier string `json:"bag_group_identifier"` StorageOption string `json:"storage_option"` BagItProfileIdentifier string `json:"bagit_profile_identifier" pg:"bagit_profile_identifier"` SourceOrganization string `json:"source_organization"` InternalSenderIdentifier string `json:"internal_sender_identifier"` InternalSenderDescription string `json:"internal_sender_description"` Institution *Institution `json:"institution" pg:"rel:has-one"` GenericFiles []*GenericFile `json:"generic_files" pg:"rel:has-many"` PremisEvents []*PremisEvent `json:"premis_events" pg:"rel:has-many"` }
func CreateObjectWithRelations ¶
func CreateObjectWithRelations() (*IntellectualObject, error)
func GetTestObject ¶
func GetTestObject() *IntellectualObject
GetTestObject returns an IntellectualObject with valid settings that can be altered per-test.
func IntellectualObjectByID ¶
func IntellectualObjectByID(id int64) (*IntellectualObject, error)
IntellectualObjectByID returns the object with the specified id. Returns pg.ErrNoRows if there is no match.
func IntellectualObjectByIdentifier ¶
func IntellectualObjectByIdentifier(identifier string) (*IntellectualObject, error)
IntellectualObjectByIdentifier returns the object with the specified identifier. Returns pg.ErrNoRows if there is no match.
func IntellectualObjectGet ¶
func IntellectualObjectGet(query *Query) (*IntellectualObject, error)
IntellectualObjectGet returns the first object matching the query.
func IntellectualObjectSelect ¶
func IntellectualObjectSelect(query *Query) ([]*IntellectualObject, error)
IntellectualObjectSelect returns all objects matching the query.
func RandomObject ¶
func RandomObject() *IntellectualObject
func (*IntellectualObject) ActiveDeletionWorkItem ¶
func (obj *IntellectualObject) ActiveDeletionWorkItem() (*WorkItem, error)
func (*IntellectualObject) AssertDeletionPreconditions ¶
func (obj *IntellectualObject) AssertDeletionPreconditions() error
func (*IntellectualObject) Delete ¶
func (obj *IntellectualObject) Delete() error
Delete soft-deletes this object by setting State to 'D' and the UpdatedAt timestamp to now. You can undo this with Undelete. It also creates a deletion PremisEvent. You can't get rid of that.
It is legitimate for a depositor to delete an object, then re-upload it later, particularly if they want to change the storage option. In that case, the object's state would be set back to "A" after the new ingest, and the old deletion event would remain to show that an earlier version of the object was once deleted.
We would know the new object is active because state = "A" and it would have an ingest event dated after the last deletion event.
func (*IntellectualObject) DeletionRequest ¶
func (obj *IntellectualObject) DeletionRequest(workItemID int64) (*DeletionRequestView, error)
func (*IntellectualObject) HasActiveFiles ¶
func (obj *IntellectualObject) HasActiveFiles() (bool, error)
HasActiveFiles returns true if this object has any active (non-deleted) files. We need to check this before marking an object as deleted. Do not mark deleted until all files have been marked deleted.
func (*IntellectualObject) IsGlacierOnly ¶
func (obj *IntellectualObject) IsGlacierOnly() bool
IsGlacierOnly returns true if this object is stored only in Glacier.
func (*IntellectualObject) LastDeletionEvent ¶
func (obj *IntellectualObject) LastDeletionEvent() (*PremisEvent, error)
LastDeleationEvent returns the latest deletion event for this object, which may be nil.
func (*IntellectualObject) LastIngestEvent ¶
func (obj *IntellectualObject) LastIngestEvent() (*PremisEvent, error)
LastIngestEvent returns the latest ingest event for this object. This should never be nil.
func (*IntellectualObject) NewDeletionEvent ¶
func (obj *IntellectualObject) NewDeletionEvent() (*PremisEvent, error)
func (*IntellectualObject) Save ¶
func (obj *IntellectualObject) Save() error
Save saves this object to the database. This will peform an insert if IntellectualObject.ID is zero. Otherwise, it updates.
func (*IntellectualObject) Validate ¶
func (obj *IntellectualObject) Validate() *common.ValidationError
func (*IntellectualObject) ValidateChanges ¶
func (obj *IntellectualObject) ValidateChanges(updatedObj *IntellectualObject) error
type IntellectualObjectCount ¶
type IntellectualObjectView ¶
type IntellectualObjectView struct { ID int64 `json:"id"` Title string `json:"title"` Description string `json:"description"` Identifier string `json:"identifier"` AltIdentifier string `json:"alt_identifier"` Access string `json:"access"` BagName string `json:"bag_name"` InstitutionID int64 `json:"institution_id"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` State string `json:"state"` ETag string `json:"etag" pg:"etag"` BagGroupIdentifier string `json:"bag_group_identifier"` StorageOption string `json:"storage_option"` BagItProfileIdentifier string `json:"bagit_profile_identifier" pg:"bagit_profile_identifier"` SourceOrganization string `json:"source_organization"` InternalSenderIdentifier string `json:"internal_sender_identifier"` InternalSenderDescription string `json:"internal_sender_description"` InstitutionName string `json:"institution_name"` InstitutionIdentifier string `json:"institution_identifier"` InstitutionType string `json:"institution_type"` InstitutionParentID int64 `json:"institution_parent_id"` FileCount int64 `json:"file_count"` Size int64 `json:"size"` PayloadFileCount int64 `json:"payload_file_count"` PayloadSize int64 `json:"payload_size"` // contains filtered or unexported fields }
func IntellectualObjectViewByID ¶
func IntellectualObjectViewByID(id int64) (*IntellectualObjectView, error)
IntellectualObjectViewByID returns the object with the specified id. Returns pg.ErrNoRows if there is no match.
func IntellectualObjectViewByIdentifier ¶
func IntellectualObjectViewByIdentifier(identifier string) (*IntellectualObjectView, error)
IntellectualObjectViewByIdentifier returns the object with the specified identifier. Returns pg.ErrNoRows if there is no match.
func IntellectualObjectViewGet ¶
func IntellectualObjectViewGet(query *Query) (*IntellectualObjectView, error)
IntellectualObjectViewGet returns the first object matching the query.
func IntellectualObjectViewSelect ¶
func IntellectualObjectViewSelect(query *Query) ([]*IntellectualObjectView, error)
IntellectualObjectViewSelect returns all objects matching the query.
func SmallestObjectNotRestoredInXDays ¶
func SmallestObjectNotRestoredInXDays(institutionID, minSize int64, days int) (*IntellectualObjectView, error)
SmallestObjectNotRestoredInXDays returns the smallest intellectual object belonging to an institutition that has not been restored in at least X days. We use this for restoration spot tests because 1) we don't want to restore an item the depositor has recently restored, and 2) we don't want to restore massive objects (hundreds of GB) if we can help it.
Param institutionID is the ID of the depositing institution. minSize is the minimum size of the object to restore. This should generally be around 1-20 KB. days is the number of days since last restoration. This should be 365 or more for spot tests, perferably 730 or more.
func (*IntellectualObjectView) GetID ¶
func (obj *IntellectualObjectView) GetID() int64
type InternalMetadata ¶
type InternalMetadata struct { TimestampModel Key string Value string // contains filtered or unexported fields }
InternalMetadata contains metadata about the state of the database. This is a holdover from Rails and ActiveRecord which turns out to be useful for housekeeping.
We primarily use it as a kind of locking mechanism to ensure that the database's internal processes don't overlap. Internal processes set a key and value when they're running, then clear the value when they're done.
For example, you'll see pairs like "update_counts is running" = true when the long-running update_counts function is doing its work. This prevents a second process from starting update_counts before the last process has completed, thus avoiding deadlock.
Registry uses this table when running restoration spot tests, which should run once per day. While we may have two or more Registry instances running at once, we want to make sure restoration spot tests run **only once** per day. This table helps with that.
func InternalMetadataByKey ¶
func InternalMetadataByKey(key string) (*InternalMetadata, error)
InternalMetadataByKey returns the file with the specified key. The key column has a unique constraint, so this should return one record, max. Returns pg.ErrNoRows if there is no match.
func InternalMetadataGet ¶
func InternalMetadataGet(query *Query) (*InternalMetadata, error)
InternalMetadataGet returns the first file matching the query.
func InternalMetadataSelect ¶
func InternalMetadataSelect(query *Query) ([]*InternalMetadata, error)
InternalMetadataSelect returns all files matching the query.
func NewInteralMetadata ¶
func NewInteralMetadata(key, value string) *InternalMetadata
NewInternalMetadata creates a new InternalMetadata record.
func (*InternalMetadata) Delete ¶
func (im *InternalMetadata) Delete() error
Delete is not supported because these records are required for internal housekeeping. This method will always return an error. We define to tell developers explicitly not to do this.
func (*InternalMetadata) Save ¶
func (im *InternalMetadata) Save() error
Save saves this record to the database. This will peform an insert if InternalMetadata.ID is zero or an update otherwise.
func (*InternalMetadata) Validate ¶
func (im *InternalMetadata) Validate() *common.ValidationError
type ParamFilter ¶
type ParamFilter struct { // Key is the name of the query string param. Key string // Column is derived from Key, and is the name of a database column Column string // RawOp is the operator in Key. For example, "eq" or "gt". RawOp string // SQLOp is the SQL operator that corresponds to RawOp. For example, // "=" or ">". SQLOp string // Values are the values attached to Key in the query string. Values []string }
ParamFilter parses query string params into filters that can be added to a SQL where clause.
func NewParamFilter ¶
func NewParamFilter(key string, values []string) (*ParamFilter, error)
NewParamFilter returns a new ParamFilter object based on the key and values submitted in the query string. It will return a custom error if it can't parse the key or values. The caller should log the error and return a basic common.ErrInvalidParam.
func (*ParamFilter) AddToQuery ¶
func (pf *ParamFilter) AddToQuery(q *Query) error
AddToQuery adds this ParamFilter to SQL query q. If it can't map the RawOp to a known Query method, it returns a custom error. The caller should log the error and then return a basic common.ErrInvalidParam.
func (*ParamFilter) ChipLabel ¶
func (p *ParamFilter) ChipLabel() string
ChipLabel returns a label to display on filter chips in the web UI.
func (*ParamFilter) ChipValue ¶
func (p *ParamFilter) ChipValue() string
ChipValue returns a value to display on filter chips in the web UI.
func (*ParamFilter) InterfaceValues ¶
func (pf *ParamFilter) InterfaceValues() []interface{}
InterfaceValues converts []string Values to []interface{} values. We get string values from the HTTP query string, but we need to provide interface{} values to the pg library that will query the database. Golang type suckage.
type PremisEvent ¶
type PremisEvent struct { TimestampModel Agent string `json:"agent"` DateTime time.Time `json:"date_time"` Detail string `json:"detail"` EventType string `json:"event_type"` GenericFileID int64 `json:"generic_file_id"` Identifier string `json:"identifier"` InstitutionID int64 `json:"institution_id"` IntellectualObjectID int64 `json:"intellectual_object_id"` Object string `json:"object"` OldUUID string `json:"old_uuid"` Outcome string `json:"outcome"` OutcomeDetail string `json:"outcome_detail"` OutcomeInformation string `json:"outcome_information"` }
func PremisEventByID ¶
func PremisEventByID(id int64) (*PremisEvent, error)
PremisEventByID returns the event with the specified id. Returns pg.ErrNoRows if there is no match.
func PremisEventByIdentifier ¶
func PremisEventByIdentifier(identifier string) (*PremisEvent, error)
PremisEventByIdentifier returns the event with the specified identifier. Returns pg.ErrNoRows if there is no match.
func PremisEventGet ¶
func PremisEventGet(query *Query) (*PremisEvent, error)
PremisEventGet returns the first event matching the query.
func PremisEventSelect ¶
func PremisEventSelect(query *Query) ([]*PremisEvent, error)
PremisEventSelect returns all events matching the query.
func RandomPremisEvent ¶
func RandomPremisEvent(eventType string) *PremisEvent
RandomPremisEvent returns a random premis event of the specified type. Caller should set GenericFileID and IntellectualObjectID.
func (*PremisEvent) Save ¶
func (event *PremisEvent) Save() error
Save saves this event to the database. This will peform an insert if PremisEvent.ID is zero. Otherwise, it updates.
func (*PremisEvent) Validate ¶
func (event *PremisEvent) Validate() *common.ValidationError
Validate returns errors if this event isn't valid.
type PremisEventCount ¶
type PremisEventView ¶
type PremisEventView struct { ID int64 `json:"id" form:"id"` Agent string `json:"agent"` CreatedAt time.Time `json:"created_at"` DateTime time.Time `json:"date_time"` Detail string `json:"detail"` EventType string `json:"event_type"` GenericFileID int64 `json:"generic_file_id"` GenericFileIdentifier string `json:"generic_file_identifier"` Identifier string `json:"identifier"` InstitutionID int64 `json:"institution_id"` InstitutionName string `json:"institution_name"` IntellectualObjectID int64 `json:"intellectual_object_id"` IntellectualObjectIdentifier string `json:"intellectual_object_identifier"` Object string `json:"object"` OldUUID string `json:"old_uuid"` Outcome string `json:"outcome"` OutcomeDetail string `json:"outcome_detail"` OutcomeInformation string `json:"outcome_information"` UpdatedAt time.Time `json:"updated_at"` // contains filtered or unexported fields }
func PremisEventViewByID ¶
func PremisEventViewByID(id int64) (*PremisEventView, error)
PremisEventViewByID returns the event with the specified id. Returns pg.ErrNoRows if there is no match.
func PremisEventViewByIdentifier ¶
func PremisEventViewByIdentifier(identifier string) (*PremisEventView, error)
PremisEventViewByIdentifier returns the event with the specified identifier. Returns pg.ErrNoRows if there is no match.
func PremisEventViewGet ¶
func PremisEventViewGet(query *Query) (*PremisEventView, error)
PremisEventViewGet returns the first event matching the query.
func PremisEventViewSelect ¶
func PremisEventViewSelect(query *Query) ([]*PremisEventView, error)
PremisEventViewSelect returns all events matching the query.
type Query ¶
type Query struct {
// contains filtered or unexported fields
}
Query provides a fluent model for constructing SQL queries, though it currently constructs only the where, order by, limit and offset clauses, which is all we need to pass to the go-pg adapter. The adapter knows how to construct the select and from clauses based on the model.
Query's functionality is a subset of go-pg's query builder features. It doesn't support joins, for example, though it does support relations.
Query exists to help the web front-end construct queries based on named inputs in GET requests. The web.FilterCollection functions can dynamically translate query string params into complex where clauses like "name ilike '%homer%' and age >= 31 and city not in ('Shelbyville', 'Atlanta', 'New York')".
We decided to omit complex joins in our dynamic queries and create SQL views instead, because after several years in production, we already know virtually all of the ways users want to join tables. Views allow us to issue simple queries, which this package supports.
func (*Query) BetweenExclusive ¶
func (*Query) BetweenInclusive ¶
func (*Query) CopyForCount ¶
CopyForCount returns a copy of this query suitable for querying one of our counts views. See pgmodels/counts.go for usage.
func (*Query) GetColumns ¶
func (*Query) GetColumnsInWhereClause ¶
func (*Query) GetOrderBy ¶
func (*Query) GetRelations ¶
func (*Query) MakePlaceholders ¶
func (*Query) OrderBy ¶
OrderBy adds an "order by" clause to the query. You can add as many of these as you want. If direction is not "desc" it will be coerced to "asc". Param column will be sanitized, removing all but alphanumeric and underscore characters.
func (*Query) Select ¶
Select executes a query and stores the result in structOrSlice, which should be either a pointer to a struct (if you want a single result) or a slice of pointers if you want multiple results. Returns an error if there is one.
Example:
user := User{} err := query.Select(&user)
or
var users []*User err := query.Select(&users)
func (*Query) WhereClause ¶
func (*Query) WhereNotIn ¶
type SchemaMigration ¶
SchemaMigration represents a schema migration record from the database. These tell us which migrations have been run. This model is read-only.
func SchemaMigrationSelect ¶
func SchemaMigrationSelect(query *Query) ([]*SchemaMigration, error)
SchemaMigrationSelect returns all records matching the query.
type SortParam ¶
func NewSortParam ¶
NewSortParam creates a new sort parameter to add to a query.
Sorts will appear on the query string like this:
sort=updated_at__desc&sort=user_id__asc
That means sort first by updated_at descending, then by user_id ascending. If sort direction is missing or invalid, it defaults to asc.
type StorageOption ¶
type StorageOption struct { BaseModel Provider string `json:"provider"` Service string `json:"service"` Region string `json:"region"` Name string `json:"name"` CostGBPerMonth float64 `json:"cost_gb_per_month"` Comment string `json:"comment"` UpdatedAt time.Time `json:"updated_at"` }
StorageOption contains information about APTrust storage option costs. This is used mainly in monthly cost reporting.
func StorageOptionByID ¶
func StorageOptionByID(id int64) (*StorageOption, error)
StorageOptionByID returns the option with the specified id. Returns pg.ErrNoRows if there is no match.
func StorageOptionByName ¶
func StorageOptionByName(name string) (*StorageOption, error)
func StorageOptionGet ¶
func StorageOptionGet(query *Query) (*StorageOption, error)
StorageOptionGet returns the first option matching the query.
func StorageOptionGetAll ¶
func StorageOptionGetAll() ([]*StorageOption, error)
func StorageOptionSelect ¶
func StorageOptionSelect(query *Query) ([]*StorageOption, error)
StorageOptionSelect returns all options matching the query.
func (*StorageOption) Save ¶
func (option *StorageOption) Save() error
Save saves this StorageOption to the database. This will peform an insert if StorageOption.ID is zero. Otherwise, it updates.
func (*StorageOption) Validate ¶
func (option *StorageOption) Validate() *common.ValidationError
Validate validates the model. This is called automatically on insert and update.
type StorageRecord ¶
type StorageRecord struct { ID int64 `json:"id" pg:"id"` GenericFileID int64 `json:"generic_file_id"` URL string `json:"url" form:"url" pg:"url"` GenericFile *GenericFile `json:"-" pg:"rel:has-one"` }
func RandomStorageRecord ¶
func RandomStorageRecord() *StorageRecord
RandomStorageRecord() returns a random storage record. Caller should set GenericFileID.
func StorageRecordByID ¶
func StorageRecordByID(id int64) (*StorageRecord, error)
StorageRecordByID returns the file with the specified id. Returns pg.ErrNoRows if there is no match.
func StorageRecordGet ¶
func StorageRecordGet(query *Query) (*StorageRecord, error)
StorageRecordGet returns the first file matching the query.
func StorageRecordSelect ¶
func StorageRecordSelect(query *Query) ([]*StorageRecord, error)
StorageRecordSelect returns all files matching the query.
func (*StorageRecord) GetID ¶
func (sr *StorageRecord) GetID() int64
func (*StorageRecord) Save ¶
func (sr *StorageRecord) Save() error
Save saves this file to the database. This will peform an insert if StorageRecord.ID is zero. Otherwise, it updates.
func (*StorageRecord) Validate ¶
func (sr *StorageRecord) Validate() *common.ValidationError
type TimestampModel ¶
type TimestampModel struct { BaseModel CreatedAt time.Time `bun:",nullzero" json:"created_at,omitempty"` UpdatedAt time.Time `bun:",nullzero" json:"updated_at,omitempty"` }
func (*TimestampModel) SetTimestamps ¶
func (tsm *TimestampModel) SetTimestamps()
type User ¶
type User struct { TimestampModel // Name is the user's display name. Name string `json:"name" pg:"name"` // Email is used to login. Must be unique. Email string `json:"email" pg:"email"` // PhoneNumber should start with + country code (e.g. +1 for US). // This number is used for SMS two-factor auth, so it should be // a mobile phone. PhoneNumber string `json:"phone_number" pg:"phone_number"` // EncryptedPassword is the user's password, encrypted. EncryptedPassword string `json:"-" form:"-" pg:"encrypted_password"` // ResetPasswordToken is an encrypted version of the token sent to a // user who wants to reset their password. The plaintext version of // this is emailed to the user. ResetPasswordToken string `json:"-" form:"-" pg:"reset_password_token"` // ResetPasswordSentAt is a timestamp describing when we sent a password // reset email. The ResetPasswordToken should be valid for only a few // minutes after this timestamp. ResetPasswordSentAt time.Time `json:"reset_password_sent_at" form:"-" pg:"reset_password_sent_at"` // RememberCreatedAt - ??? - Legacy field from Devise, probably related // to time-based OTPs. Not used. RememberCreatedAt time.Time `json:"-" form:"-" pg:"remember_created_at"` // SignInCount is the number of times this user has successfully signed in. SignInCount int `json:"sign_in_count" form:"-" pg:"sign_in_count,use_zero"` // CurrentSignInAt is a timestamp describing when this user signed // in for their current session. CurrentSignInAt time.Time `json:"current_sign_in_at" form:"-" pg:"current_sign_in_at"` // LastSignInAt is a timestamp describing when this user signed // in for their previous session. LastSignInAt time.Time `json:"last_sign_in_at" form:"-" pg:"last_sign_in_at"` // CurrentSignInIP is the IP address from which user signed in. CurrentSignInIP string `json:"current_sign_in_ip" form:"-" pg:"current_sign_in_ip"` // LastSignInIP is the IP address from which user signed in for their // prior session. LastSignInIP string `json:"last_sign_in_ip" form:"-" pg:"last_sign_in_ip"` // InstitituionID is the id of the institution to which this user // belongs. InstitutionID int64 `json:"institution_id" pg:"institution_id"` // EncryptedAPISecretKey is the user's encrypted API key. This may // be empty if the user has never requested a key. EncryptedAPISecretKey string `json:"-" form:"-" pg:"encrypted_api_secret_key"` // PasswordChangedAt is the date and time the user last changed their // password. PasswordChangedAt time.Time `json:"password_changed_at" form:"-" pg:"password_changed_at"` // EncryptedOTPSecret is the encrypted version of a user's one-time // password. The plaintext is usually a six-digit code sent via SMS. // This will be empty if we didn't send a code, or if the user has // correctly entered it and completed two-factor login. EncryptedOTPSecret string `json:"-" form:"-" pg:"encrypted_otp_secret"` // EncryptedOTPSecretIV is a legacy field from Devise. Not used. // TODO: Delete this. EncryptedOTPSecretIV string `json:"-" form:"-" pg:"encrypted_otp_secret_iv"` // EncryptedOTPSecretSalt is a legacy field from Devise. Not used. EncryptedOTPSecretSalt string `json:"-" form:"-" pg:"encrypted_otp_secret_salt"` // EncryptedOTPSentAt describes when we sent a one-time password // via text/SMS. We track this because these passwords should be // valid only for a limited time. This field be empty except when // we're waiting for a user to enter a text/SMS OTP. EncryptedOTPSentAt time.Time `json:"-" form:"-" pg:"encrypted_otp_sent_at"` // ConsumedTimestep is a legacy field from Devise, which used it // for time-based one-time passwords. Not used. // TODO: Delete this. ConsumedTimestep int `json:"-" form:"-" pg:"consumed_timestep"` // OTPRequiredForLogin indicates whether, as a matter of policy, the // user must use some form of OTP to log in. If true, the user should // be allowed to log in only with Authy one-touch, six-digit SMS // code, or backup code. // // Use IsTwoFactorUser() to actually determine whether we should // force this user to use Authy, SMS, or backup code to get it. // This is messy because it has to mirror the legacy Rails implementation // for now. OTPRequiredForLogin bool `json:"otp_required_for_login" pg:"otp_required_for_login"` // DeactivatedAt is a timestamp describing when this user was // deactivated. For most users, it will be empty. APTrust admin and // Institutional Admin can disable other users. Then can also // re-enable a user by clearing this flag. DeactivatedAt time.Time `json:"deactivated_at" form:"-" pg:"deactivated_at"` // EnabledTwoFactor indicates whether the user's account has // enabled two factor authentication. See also ConfirmedTwoFactor. EnabledTwoFactor bool `json:"enabled_two_factor" form:"-" pg:"enabled_two_factor"` // ConfirmedTwoFactor indicates that the system has confirmed this // user's phone number (for SMS) and Authy account (for Authy 2FA). ConfirmedTwoFactor bool `json:"confirmed_two_factor" form:"-" pg:"confirmed_two_factor"` // OTPBackupCodes is a list of backup codes the user can use to // log if they can't get in via SMS or Authy. OTPBackupCodes []string `json:"-" form:"-" pg:"otp_backup_codes,array"` // AuthyID is the user's Authy ID. We need this to send them push // messages to complete one-touch sign-in. This will be empty for // those who don't use Authy. AuthyID string `json:"-" form:"-" pg:"authy_id"` // LastSignInWithAuthy is the timestamp of this user's last // successful sign-in with Authy. LastSignInWithAuthy time.Time `json:"last_sign_in_with_authy" form:"-" pg:"last_sign_in_with_authy"` // AuthyStatus indicates how the user wants to authenticate with // Authy. If it's constants.TwoFactorAuthy, we should send them a // push, so they can login with one-touch. Anything else means SMS, // but call IsTwoFactorUser() to make sure they're actually require // two-factor auth before trying to text them. AuthyStatus string `json:"authy_status" pg:"authy_status"` // EmailVerified will be true once the system has verified that the // user's email address is correct. EmailVerified bool `json:"email_verified" form:"-" pg:"email_verified"` // InitialPasswordUpdated will be true once a user updates their // initial password. When we create a new user, we generate a random // password, then send them an email with a login link. At that // point, the user has to set their own password. InitialPasswordUpdated bool `json:"initial_password_updated" form:"-" pg:"initial_password_updated"` // ForcePasswordUpdate indicated whether the user will be forced to // update their password the next time they visit. ForcePasswordUpdate bool `json:"force_password_update" form:"-" pg:"force_password_update"` // GracePeriod is a legacy field from the old Rails app. It held the // date by which a user MUST complete either Authy or SMS two-factor // setup. This feature was universally despised, and we won't be // using it unless someone complains. For now, consider this as // unused. GracePeriod time.Time `json:"grace_period" time_format:"2006-01-02" pg:"grace_period"` // AwaitingSecondFactor indicates that the user has logged in with // email and password, but has not yet completed the second login // step (Authy, SMS OTP, or backup code). This flag is only set on // users going through the two-factor process. Middleware checks it // to prevent partially logged-in users from accessing any pages other // than those required to complete the two-factor login process. AwaitingSecondFactor bool `json:"-" pg:"awaiting_second_factor,use_zero"` // Role is the user's role. Role string `json:"role" pg:"role"` // Institution is where they lock you up after you've spent too much // time trying to figure out the old Rails code. Institution *Institution `json:"institution" pg:"rel:has-one"` }
User is a person who can log in and do stuff. Most of this model was inherited from the old Rails app. It includes a number of obsolete fields that we should remove after we're stable in production.
func UserByEmail ¶
UserByEmail returns the user with the specified email address. Returns pg.ErrNoRows if there is no match.
func UserByID ¶
UserByID returns the institution with the specified id. Returns pg.ErrNoRows if there is no match.
func UserSelect ¶
UserSelect returns all user matching the query.
func UserSignIn ¶
UserSignIn signs a user in. If successful, it returns the User record with User.Institution properly set. If it fails, check the error.
func (*User) ClearOTPSecret ¶
ClearOTPSecret deletes the user's EncryptedOTPSecret.
func (*User) CountryCodeAndPhone ¶
CountryCodeAndPhone returns this user's country code and phone number.
func (*User) CreateOTPToken ¶
CreateOTPToken creates a new one-time password token, typically used for SMS-based two-factor authentication. It saves an encrypted version of the token to the database and returns the plaintext version of the token. For SMS, we use six-digit tokens because they're easy for a user to type.
func (*User) HasPermission ¶
func (user *User) HasPermission(action constants.Permission, institutionID int64) bool
HasPermission returns true or false to indicate whether the user has sufficient permissions to perform the requested action. Param action should be one of the constants from constants/permissions.go. Param institutionID should be the ID of the institution that owns the object upon which the user is trying to act. In certain cases, such as when a user is editing him/herself, this can be zero.
func (*User) IsAdmin ¶
IsAdmin returns true if user is a Sys Admin. Returns false for all other roles (including institutional admin, which is not a super user).
func (*User) IsAuthyOneTouchUser ¶
IsAuthyOneTouchUser returns true if the user has enabled Authy one touch for two-factor login.
func (*User) IsSMSUser ¶
IsSMSUser returns true if this user has enabled two-factor authentication with SMS/text message.
func (*User) IsTwoFactorUser ¶
IsTwoFactorUser returns true if this user has enabled and confirmed two factor authentication.
Sorry... For now, we have to work with the convoluted logic of the old Rails app. Hence the confusion between this and OTPRequiredForLogin.
func (*User) ToMin ¶
ToMin returns a UserMin struct containing only enough info to identify a user. This subset of info is safe to expose through member API endpoints.
func (*User) TwoFactorMethod ¶
TwoFactorMethod returns one of the following:
constants.TwoFactorNone if the user does not use two-factor auth.
constants.TwoFactorAuthy if the user uses two-factor auth via Authy.
constants.TwoFactorSMS if the user receives two-factor OTP code via text/SMS
func (*User) Validate ¶
func (user *User) Validate() *common.ValidationError
type UserMin ¶
UserMin contains minimum required information to identify a user. This is used for serialization in parts of the member API when we want to show which user is attached to a record (such as a deletion request) but we do not want to expose unnecessary information about that user.
type UserView ¶
type UserView struct { ID int64 `json:"id" pg:"id"` Name string `json:"name" pg:"name"` Email string `json:"email" pg:"email"` PhoneNumber string `json:"phone_number" pg:"phone_number"` CreatedAt time.Time `json:"created_at" pg:"created_at"` UpdatedAt time.Time `json:"updated_at" pg:"updated_at"` ResetPasswordSentAt time.Time `json:"reset_password_sent_at" pg:"reset_password_sent_at"` RememberCreatedAt time.Time `json:"-" pg:"remember_created_at"` SignInCount int `json:"sign_in_count" pg:"sign_in_count,use_zero"` CurrentSignInAt time.Time `json:"current_sign_in_at" pg:"current_sign_in_at"` LastSignInAt time.Time `json:"last_sign_in_at" pg:"last_sign_in_at"` CurrentSignInIP string `json:"current_sign_in_ip" pg:"current_sign_in_ip"` LastSignInIP string `json:"last_sign_in_ip" pg:"last_sign_in_ip"` InstitutionID int64 `json:"institution_id" pg:"institution_id"` PasswordChangedAt time.Time `json:"password_changed_at" pg:"password_changed_at"` ConsumedTimestep int `json:"-" pg:"consumed_timestep"` OTPRequiredForLogin bool `json:"otp_required_for_login" pg:"otp_required_for_login"` DeactivatedAt time.Time `json:"deactivated_at" pg:"deactivated_at"` EnabledTwoFactor bool `json:"enabled_two_factor" pg:"enabled_two_factor"` ConfirmedTwoFactor bool `json:"confirmed_two_factor" pg:"confirmed_two_factor"` AuthyID string `json:"-" pg:"authy_id"` LastSignInWithAuthy time.Time `json:"last_sign_in_with_authy" pg:"last_sign_in_with_authy"` AuthyStatus string `json:"authy_status" pg:"authy_status"` EmailVerified bool `json:"email_verified" pg:"email_verified"` InitialPasswordUpdated bool `json:"initial_password_updated" pg:"initial_password_updated"` ForcePasswordUpdate bool `json:"force_password_update" pg:"force_password_update"` GracePeriod time.Time `json:"grace_period" pg:"grace_period"` Role string `json:"role" pg:"role"` InstitutionName string `json:"institution_name" pg:"institution_name"` InstitutionIdentifier string `json:"institution_identifier" pg:"institution_identifier"` InstitutionState string `json:"institution_state" pg:"institution_state"` InstitutionType string `json:"institution_type" pg:"institution_type"` MemberInstitutionId int64 `json:"member_institution_id" pg:"member_institution_id"` MemberInstitutionName string `json:"member_institution_name" pg:"member_institution_name"` MemberInstitutionIdentifier string `json:"member_institution_identifier" pg:"member_institution_identifier"` MemberInstitutionState string `json:"member_institution_state" pg:"member_institution_state"` OTPEnabled bool `json:"otp_enabled" pg:"otp_enabled"` ReceivingBucket string `json:"receiving_bucket" pg:"receiving_bucket"` RestoreBucket string `json:"restore_bucket" pg:"restore_bucket"` // contains filtered or unexported fields }
func UserViewByEmail ¶
UserViewByEmail returns the UserView record with the specified email address. Returns pg.ErrNoRows if there is no match.
func UserViewByID ¶
UserViewByID returns the UserView record with the specified id. Returns pg.ErrNoRows if there is no match.
func UserViewGet ¶
UserViewGet returns the first user view record matching the query.
func UserViewSelect ¶
UserViewSelect returns all UserView records matching the query. This read-only view is for listing users. It includes a number of insitition fields to simplify the search process.
type WorkItem ¶
type WorkItem struct { TimestampModel Name string `json:"name" pg:"name"` ETag string `json:"etag" pg:"etag"` InstitutionID int64 `json:"institution_id"` IntellectualObjectID int64 `json:"intellectual_object_id"` GenericFileID int64 `json:"generic_file_id"` Bucket string `json:"bucket"` User string `json:"user"` Note string `json:"note"` Action string `json:"action"` Stage string `json:"stage"` Status string `json:"status"` Outcome string `json:"outcome"` BagDate time.Time `json:"bag_date"` DateProcessed time.Time `json:"date_processed"` Retry bool `json:"retry" pg:",use_zero"` Node string `json:"node"` PID int `json:"pid"` NeedsAdminReview bool `json:"needs_admin_review" pg:",use_zero"` QueuedAt time.Time `json:"queued_at"` Size int64 `json:"size"` StageStartedAt time.Time `json:"stage_started_at"` APTrustApprover string `json:"aptrust_approver" pg:"aptrust_approver"` InstApprover string `json:"inst_approver"` }
WorkItem contains information about a task or suite of related tasks to be performed by the preservation services workers, such as ingest, restoration, and deletion. While preservation services uses Redis to track interim processing data as it works, WorkItem records here in the registry keep a record that's visible to both depositors and APTrust admins.
These high-level records let us know whether a task is pending, in process, or completed. They also let us know the outcome and what specific errors may have occurred.
WorkItems cannot be deleted because they're part of our system's audit trail.
func LastSuccessfulIngest ¶
LastSuccessfulIngest returns the last successful ingest WorkItem for the specified intellectual object id.
func NewDeletionItem ¶
func NewDeletionItem(obj *IntellectualObject, gf *GenericFile, requestedBy, approvedBy *User) (*WorkItem, error)
NewDeletionItem creates a new work item to delete a file or object. Param obj is required. If gf is not nil, this will create a WorkItem to delete file gf. Otherwise, it creates a WorkItem to delete object obj.
Param requestedBy is the User who initially requested the deletion. Param approvedBy is the User who approved the deletion request. These two are required.
func NewItemFromLastSuccessfulIngest ¶
NewItemFromLastSuccessfulIngest creates a new WorkItem based on the last successful ingest WorkItem of the specified object. This is used for creating various deletion and restoration WorkItems. The returned WorkItem will include the proper object name, object id, object identifier and etag. All other fields will be cleared out. The caller must set essential fields like Action, User, GenericFileID (if appropriate) and the like.
This will return an error if the system can't find the last successful ingest record for the specified object.
func NewRestorationItem ¶
func NewRestorationItem(obj *IntellectualObject, gf *GenericFile, user *User) (*WorkItem, error)
NewRestorationItem creates and saves a new WorkItem for an object or file restoration.
Param obj (required) is the object to be restored. gf is the GenericFile to be restored. This can be zero if we're restoring an object instead of a file. Param user is the user initiating the restoration.
Before creating a restoration WorkItem, the caller should ensure that the object and file have no pending work items. See WorkItemsPendingForObject() and WorkItemsPendinForFile().
func RandomWorkItem ¶
func WorkItemByID ¶
WorkItemByID returns the work item with the specified id. Returns pg.ErrNoRows if there is no match.
func WorkItemGet ¶
WorkItemGet returns the first work item matching the query.
func WorkItemSelect ¶
WorkItemSelect returns all work items matching the query.
func WorkItemsPendingForFile ¶
WorkItemsPendingForFile returns a list of in-progress WorkItems for the GenericFile with the specified ID.
func WorkItemsPendingForObject ¶
WorkItemsPendingForObject returns a list of in-progress WorkItems for the IntellectualObject with the specified institution ID and bag name. We don't use an IntellectualObjectID here because when we're ingesting or re-ingesting an object, the WorkItem won't have an ObjectID until the ingest/re-ingest is complete.
This method is called before initializing a new restoration or deletion request. We specifically want to avoid the case where a user requests a restoration or deletion on an object that is about to be reingested. If that were to happen, the delete worker would be deleting files that an ingest worker just wrote. Or the ingest worker would be overwriting files that the restore worker was trying to restore.
Pharos queried by object id, which was a mistake that would not catch re-ingests. This corrects that.
func (*WorkItem) AlertOnSuccessfulSpotTest ¶
AlertOnSuccessfulSpotTest sends an email to institutional users and admins when a restoration spot test has completed. It's the institution's job to figure out what to do with the restored object.
This returns an alert if the alert was created successfully, nil otherwise. Zero does not necessarily indicate failure. It just means we didn't create an alert, and there may be valid reasons for not doing so.
func (*WorkItem) GetSpotTestDetails ¶
func (item *WorkItem) GetSpotTestDetails() (*Institution, *IntellectualObject, error)
GetSpotTestDetails returns true if this WorkItem is a restoration spot test. It also returns the Institution on whose behalf the test was conducted, and the object that was or is being restored.
func (*WorkItem) HasCompleted ¶
HasCompleted returns true if this item has completed processing.
func (*WorkItem) Save ¶
Save saves this work item to the database. This will peform an insert if WorkItem.ID is zero. Otherwise, it updates.
func (*WorkItem) SetForRequeue ¶
SetForRequeue sets properies so this item can be requeued. Note that it saves the object. It will return constants.ErrInvalidRequeue if the stage is not valid, and may return validation or pg error if the object cannot be saved.
The call is responsible for actually pushing the WorkItem.ID into the correct NSQ topic.
func (*WorkItem) Validate ¶
func (item *WorkItem) Validate() *common.ValidationError
func (*WorkItem) ValidateChanges ¶
ValidateChanges returns an error if updatedItem contains illegal changes. Don't change action on work items. Create a new work item instead. Changing any of the other IDs or identifiers leads to incorrect data, so it's prohibited.
type WorkItemCount ¶
type WorkItemView ¶
type WorkItemView struct { ID int64 `json:"id" pg:"id"` Name string `json:"name" pg:"name"` ETag string `json:"etag" pg:"etag"` InstitutionID int64 `json:"institution_id" pg:"institution_id"` InstitutionName string `json:"institution_name" pg:"institution_name"` InstitutionIdentifier string `json:"institution_identifier" pg:"institution_identifier"` IntellectualObjectID int64 `json:"intellectual_object_id" pg:"intellectual_object_id"` ObjectIdentifier string `json:"object_identifier" pg:"object_identifier"` AltIdentifier string `json:"alt_identifier" pg:"alt_identifier"` BagGroupIdentifier string `json:"bag_group_identifier" pg:"bag_group_identifier"` StorageOption string `json:"storage_option" pg:"storage_option"` BagItProfileIdentifier string `json:"bagit_profile_identifier" pg:"bagit_profile_identifier"` SourceOrganization string `json:"source_organization" pg:"source_organization"` InternalSenderIdentifier string `json:"internal_sender_identifier" pg:"internal_sender_identifier"` GenericFileID int64 `json:"generic_file_id" pg:"generic_file_id"` GenericFileIdentifier string `json:"generic_file_identifier" pg:"generic_file_identifier"` Bucket string `json:"bucket" pg:"bucket"` User string `json:"user" pg:"user"` Note string `json:"note" pg:"note"` Action string `json:"action" pg:"action"` Stage string `json:"stage" pg:"stage"` Status string `json:"status" pg:"status"` Outcome string `json:"outcome" pg:"outcome"` BagDate time.Time `json:"bag_date" pg:"bag_date"` DateProcessed time.Time `json:"date_processed" pg:"date_processed"` Retry bool `json:"retry" pg:"retry"` Node string `json:"node" pg:"node"` PID int `json:"pid" pg:"pid"` NeedsAdminReview bool `json:"needs_admin_review" pg:"needs_admin_review"` QueuedAt time.Time `json:"queued_at" pg:"queued_at"` Size int64 `json:"size" pg:"size"` StageStartedAt time.Time `json:"stage_started_at" pg:"stage_started_at"` APTrustApprover string `json:"aptrust_approver" pg:"aptrust_approver"` InstApprover string `json:"inst_approver" pg:"inst_approver"` CreatedAt time.Time `json:"created_at" pg:"created_at"` UpdatedAt time.Time `json:"updated_at" pg:"updated_at"` // contains filtered or unexported fields }
WorkItemView is a read-only model for querying. It flattens out WorkItem and some of its one-to-one relations for easy querying.
func WorkItemViewByID ¶
func WorkItemViewByID(id int64) (*WorkItemView, error)
WorkItemViewByID returns the work item with the specified id. Returns pg.ErrNoRows if there is no match.
func WorkItemViewGet ¶
func WorkItemViewGet(query *Query) (*WorkItemView, error)
WorkItemViewGet returns the first work item matching the query.
func WorkItemViewSelect ¶
func WorkItemViewSelect(query *Query) ([]*WorkItemView, error)
WorkItemViewSelect returns all work items matching the query.
func (*WorkItemView) FindIngestedObject ¶
func (item *WorkItemView) FindIngestedObject() (*IntellectualObject, error)
FindIngestedObject sounds like something the vet would do with your cat. It's actually used to fix a specific case where Registry thinks an ingest has failed, even though it actually succeeded. If we have to manually push the WorkItem to Ingest/Cleanup/Success, we need to link it to the ingested object. That object should match the identifier and etag of the WorkItem.
We rarely need to do this. This case occurs only when preserv tries to re-record an already completed ingest and accidentally overwrites the WorkItem's object id. We're still trying to track down the conditions that lead to that event, but again, it's rare.
func (*WorkItemView) GetID ¶
func (item *WorkItemView) GetID() int64
GetID returns the ID of this WorkItem.
func (*WorkItemView) GetObjIdentifier ¶
func (item *WorkItemView) GetObjIdentifier() string
ObjIdentifier returns this item's ObjectIdentifier if it exists, or what the object identifier would be if the item were fully ingested. Note that for ingest items, no object identifier is assigned until ingest is complete. However, to get a look at preservation services' internal Redis data, we need to know this not-yet-assigned identifier to compose the Redis key.
func (*WorkItemView) HasCompleted ¶
func (item *WorkItemView) HasCompleted() bool
HasCompleted returns true if this item has completed processing.
func (*WorkItemView) IngestObjectLinkIsMissing ¶
func (item *WorkItemView) IngestObjectLinkIsMissing() bool
IngestObjectLinkIsMissing returns true if this WorkItemView should have an associated IntellectualObjectID but does not have it.
func (*WorkItemView) Validate ¶
func (item *WorkItemView) Validate() *common.ValidationError
Validate is a no-op. This view is not writable, so we can't save to it. This method is here to satisfy the Model interface.
Source Files ¶
- alert.go
- alert_view.go
- billing_stats.go
- checksum.go
- checksum_view.go
- counts.go
- deletion_request.go
- deletion_request_view.go
- deposit_format_stats.go
- deposit_stats.go
- factory.go
- filter_collection.go
- generic_file.go
- generic_file_view.go
- institution.go
- institution_view.go
- intellectual_object.go
- intellectual_object_view.go
- internal_metadata.go
- json_types.go
- pgmodel.go
- premis_event.go
- premis_event_view.go
- query.go
- schema_migrations.go
- storage_option.go
- storage_record.go
- user.go
- user_view.go
- work_item.go
- work_item_view.go