# apostrophe-pieces
# Inherits from: apostrophe-doc-type-manager
apostrophe-pieces
provides a "base class" you can extend to create new content
types for your project. Just use the addFields
option to create a schema and
you'll get a user interface for managing your content for free. Add in the
apostrophe-pieces-pages
module to display an index page and permalink pages
for your pieces, and use apostrophe-pieces-widgets
to allow them to be sprinkled
into pages all over the site. To learn more, see:
# Options
# slugPrefix
If set this string, which typically should end with -
, will be prepended
to the slugs of all pieces of this type in order to prevent needless
conflicts with the slugs of other piece types.
# addToListProjection
A MongoDB-style projection object indicating which additional properties of a piece will be returned by the query that populates the list view in the "Manage Pieces" dialog box. This was added for security reasons. Note that if you are simply using addColumns then this should happen automatically for you. You would mainly need this option if you are overriding the list view template altogether and displaying information in a custom way. Negative projections (exclusions) are not supported.
# More Options
See reusable content with pieces for many additional options.
# Methods
# finalizeControls() [api]
# findForEditing(req, criteria, projection) [api]
Returns a cursor that finds docs the current user can edit. Unlike find(), this cursor defaults to including unpublished docs. Subclasses of apostrophe-pieces often extend this to remove more default filters
# requirePiece(req, res, next) [api]
middleware for JSON API routes that expect the ID of an existing piece at req.body._id, with editing privileges
# requirePieceEditorView(req, res, next) [api]
middleware for JSON API routes that expect the ID of an existing piece this user is allowed to edit at req.body._id
# requireEditor(req, res, next) [api]
User must have some editing privileges for this type
# list(req, options, callback) [api]
options.filters can contain cursor filters. options.chooser
, options.format
and
options.manageView
are also implemented. For bc, if options.filters
does not exist,
all properties of options are treated as cursor filters.
# getListProjection(req) [api]
Used to fetch the projection used for the /modules/yourmodulename/list route to avoid disclosing
excessive information. By default, returns the listProjection
option. A good extension point;
be sure to apply the super
pattern to get the benefit of extensions in other modules,
like workflow.
# setListProjection(req, cursor) [api]
Implements setting the projection for the list route, see getListProjection.
# insert(req, piece, options, callback) [api]
Insert a piece. Also invokes the beforeInsert
, beforeSave
, afterInsert
and
afterSave
methods of this module.
You may omit the options
argument completely.
If options.permissions
is explicitly set to false
, permissions are
not checked. Otherwise the user must have the appropriate permissions to
insert the piece.
If options.skipAttachments
is true, the operation will be slightly
faster, however this is only safe to use if both the schema of the document
and the schemas of any arrays and widgets within the document and its
areas contain no attachments. This does not include attachments
reached via joins.
For convenience, the piece is passed to the callback as the second argument. It's the same piece object, with some new properties.
If no callback is passed, returns a promise.
# update(req, piece, options, callback) [api]
Update a piece. Also invokes the beforeUpdate
, beforeSave
, afterUpdate
and
afterSave
methods of this module.
You may omit the options
argument completely.
If options.permissions
is explicitly set to false
, permissions are
not checked. Otherwise the user must have the appropriate permissions to
insert the piece.
If options.skipAttachments
is true, the operation will be slightly
faster, however this is only safe to use if both the schema of the document
and the schemas of any arrays and widgets within the document and its
areas contain no attachments. This does not include attachments
reached via joins.
For convenience, the piece is passed to the callback as the second argument.
It's the same piece object you passed, likely with modifications such as
the updatedAt
property.
# trash(req, id, callback) [api]
Move a piece to the trash by id. If callback
is omitted,
a promise is returned.
# rescue(req, id, callback) [api]
Rescue a piece from the trash by id. If callback
is omitted,
a promise is returned.
# convert(req, piece, callback) [api]
Convert the data supplied in req.body
via the schema and
update the piece object accordingly. If req.convertOnlyTheseFields
is present, touch only the fields present in that array.
# afterConvert(req, piece, callback) [api]
Invoked after apos.schemas.convert by the insert
and
update
routes
# beforeInsert(req, piece, options, callback) [api]
Invoked by self.insert
. Does nothing by default; convenient extension point
# beforeSave(req, piece, options, callback) [api]
Invoked by self.insert
and self.update
. Does nothing by default; convenient extension point
# afterInsert(req, piece, options, callback) [api]
Invoked by self.insert
. Does nothing by default; convenient extension point
# afterSave(req, piece, options, callback) [api]
Invoked by self.insert
and self.update
. Does nothing by default; convenient extension point
# beforeUpdate(req, piece, options, callback) [api]
Invoked by self.update
. Does nothing by default; convenient extension point
# afterUpdate(req, piece, options, callback) [api]
Invoked by self.update
. Does nothing by default; convenient extension point
# beforeTrash(req, id, callback) [api]
Invoked by self.trash
. Does nothing by default; convenient extension point
# afterTrash(req, id, callback) [api]
Invoked by self.trash
. Does nothing by default; convenient extension point
# beforeRescue(req, id, callback) [api]
# afterRescue(req, id, callback) [api]
# beforeList(req, filters, callback) [api]
# afterList(req, results, callback) [api]
# apiResponse(res, err, data) [api]
For legacy reasons, pieces have their own apiResponse method which is just a wrapper for the newer apiResponder.
# insertResponse(req, res, err, data) [api]
# updateResponse(req, res, err, data) [api]
# retrieveResponse(req, res, err, data) [api]
# listResponse(req, res, err, data) [api]
# trashResponse(req, res, err, data) [api]
# rescueResponse(req, res, err, data) [api]
# composeFilters() [api]
# composeColumns() [api]
# validateSchema() [api]
# searchDetermineTypes(types) [api]
Enable inclusion of this type in sitewide search results
# isAdminOnly() [api]
# addPermissions() [api]
# addToAdminBar() [api]
# addUrls(req, pieces, callback) [api]
Add ._url
properties to the given pieces, if possible.
The default implementation does nothing, however
apostrophe-pieces-pages will
call setAddUrls
to point to its own addUrlsToPieces
method.
# setAddUrls(fn) [api]
Called by apostrophe-pieces-pages to
replace the default addUrls
method with one that assigns ._url
properties to pieces based on the most suitable pages of that type.
See the addUrlsToPieces
method of apostrophe-pieces-pages
.
# composeBatchOperations() [api]
# batchSimpleRoute(req, name, change) [api]
Implements a simple batch operation like publish or unpublish.
Pass req
, the name
of a configured batch operation, and
and a function that accepts (req, piece, data, callback),
performs the modification on that one piece (including calling
update
if appropriate), and invokes its callback.
data
is an object containing any schema fields specified
for the batch operation. If there is no schema it will be
an empty object.
If req.body.job
is truthy, replies immediately to the request with
{ status: 'ok', jobId: 'cxxxx' }
. The jobId
can then
be passed to apos.modules['apostrophe-jobs'].start()
on the rowser side to
monitor progress.
Otherwise, replies to the request with { status: 'ok', data: piece }
on success. If ids
rather than _id
were specified,
data
is an empty object.
To avoid RAM issues with very large selections and ensure that lifecycle callbacks like beforeUpdate, etc. are invoked, the current implementation processes the pieces in series.
# convertInsertAndRefresh(req, responder) [api]
Accept a piece found at req.body
, via
schema-based convert mechanisms, then
invoke responder
with req, res, err, piece
.
Implements self.routes.insert
. Also used
by the optional apostrophe-pieces-rest-api
module.
If req.piece
has a _copyingId
property, fetch that
piece and, if we have permission to edit, copy its
non-schema-based top level areas into the new piece.
This accounts for content editor-modal.js doesn't know about.
# convertUpdateAndRefresh(req, responder) [api]
Update the piece object at req.piece
(usually populated via the requirePiece middleware
or by the insert route) based on req.body
, fetch the updated piece
and invoke responder
with req, res, err, piece
.
Implements the back end of the update
route, also used
by the optional apostrophe-pieces-rest-api
module.
# copyExtraAreas(req, copyFrom, piece, callback) [api]
Copy top-level areas present in copyFrom
to piece
,
leaving any that are already present in piece
alone.
The copy mechanism in the piece editor modal only
knows about noncontextual schema fields, this method is called on the
server side to copy contextual and undeclared areas too
# copyExtras(req, copyFrom, piece, callback) [api]
An empty stub you may override to copy extra properties not visible to the schema when the user carries out a "copy piece" operation. At this point schema fields and top level extra areas have already been copied
# getCreateControls(req) [api]
# getEditControls(req) [api]
# getChooserControls(req) [api]
# getManagerControls(req) [api]
# generate(i) [api]
Generate a sample piece of this type. The i
counter
is used to distinguish it from other samples. Useful
for things like testing pagination, see the
your-piece-type:generate
task.