CenterForDigitalHumanities / TPEN-services

Services required by TPEN interfaces in order to interact with data
1 stars 0 forks source link

Create Project Factory to produce Projects for the Interface or the database #114

Open cubap opened 4 months ago

cubap commented 4 months ago

Patterns not required, but well-explained here: https://www.geeksforgeeks.org/abstract-factory-pattern-javascript-design-patterns/

The API services need to be able to prepare user/application input for saving to the local database. The input and output will not match exactly as the requirements have a few required entries and lots of options. This Factory will not be used by the clients directly, but from within the Project class when "creating" a new Project, for example, as in #93.

Factory

The factory does not interact with the database - it is a convenience for a task that is expected to be repeated thousands of times. Input will be variable, and several ways will be provided for generating a new project.

Outputs

The Factory probably belongs in a factory.mjs inside the class directory. There is about to be another issue for a ProjectBuilder, btw. The expectation of any accessor is to get back something like a single Project:

  1. Simple Readonly Project {} for Public Interface User
  2. Complete detailed Project {} for Interface for Project member
  3. new Project() for doing stuff with here
  4. Complete Project document prepped for database

Inputs

Some important ways to spin up these returns should be:

  1. IIIF Manifest link or serialized IIIF Manifest/Collection Object
  2. minimal or minimal+ Object as defined below
  3. a well-described Project() instance.

Specific Specs

TODO: all possible props with how to derive them

Validation is perhaps the trickiest as some of these can be thrown very wide.

asPublicObject() Simple Public Project {}

This is the Project data object that is available for anyone. The isPublic flag concept will need to be revisited, as it is more about whether this is published to the "public projects" interfaces and probably shouldn't exist. The first check, then, is to see if the Public User has at least a readonly role in this Project (or 401 rejection).

_id *required, hexstring

The database will provide a ObjectId(hex) and this should be converted to a .toHexstring() before sending it out. Once the Static repo is up and there is a cached version of this, it should be replaced with the @id version of this with the id hexString or the slug.

created *required, immutable, Date

The creation date of the Project as timestamp.

title *required, String

The project title; may be a generated default if missing for some reason.

creator *required, URL

The Agent who created this Project

license *required, String | Object

Simple statement or abbreviation for copyright or license rights.

tags *optional

Array of tags classifying the Project

contributors *required, [ URL ]

Array of members in the connected group.

layers *optional, [ URL ]

Array of the Annotation Collections in RERUM containing this Project's annotations.

asInterfaceObject() Complete Member's Project {}

An Interface Object for an authenticated user will always be one at a time and have more configuration and metadata included.

layers *less optional, [ URL ]

For an Interface of one Project, the Layers need to be included except for the currently undescribed case where the Project is a ProjectCollection, organizing Projects instead of Layers.

contributors *required User/Permissions Map

For a known user, the contributors will be available in the Interface as an easier to access map:

"contributors": {
    "abcdef123456abcdef123456" : {
        "displayName" : "First Dude",
        "agent" : "https://store.rerum.io/v1/id/123abc123abc"
        "roles" : [ "OWNER", "LEADER", "CONTRIBUTOR" ],
        "permissions" :  {
            "members" : "MODIFY_ALL",
            "project" : "MODIFY_ALL",
            "annotations" : "MODIFY_ALL"
        }
    },
   "defdefdefdef987987987" : {
        "displayName" : "Another Fellow",
        "agent" : "https://store.rerum.io/v1/id/923abz923abz"
        "roles" : [ "CONTRIBUTOR" ],
        "permissions" :  {
            "members" : "NONE",
            "project" : "MODIFY_PAGES ADD_COLLECTIONS",
            "annotations" : "MODIFY_ALL"
        }
    }
}
manifest *required, URL

JSON link for external Manifest for Project or Static generated one in TPEN from project creation.

lastModified *required if present, URI of last saved Page

This is an autosaving bookmark of recent activity and may be made much more sophisticated in the future.

tools, options *required

Flexible and customizable stuff for controlling Interfaces or setting preferences.

asNewProject() new Project()

This just serves as a constructor for the Project class, automating the necessary bits, like "creator", and returning the new Project() or invalidating.

asDatabaseObject() Project document for database

Lots of possibilities are possible for the data passed in here, but we should validate and then reformat for the database. Pert of this may be reserved for the database driver, if appropriate to decouple it.

_id *required

Expect an integer or hexstring and save as an ObjectId(hexstring).

slug, layers, license, tools, options, tags, title

As entered, generally speaking. Most customizations should fit into options or tools but we may consider something like metadata. This Factory is probably inappropriate for that workflow anyway, since there is probably a specific Project.addTool() method in the works.

creator *required, URL

Always from token.

group *required, $oid

ObjectId(hex) of a linked document. The default Group will have the creator as the OWNER, LEADER if nothing else is provided for a new one.