Apostrophecms: Allow to upload PDF file only - node.js

I am having one field with relation. I want to upload only PDF files. Whereas I don't want to change the default setting for the dgad-attachments from app.js/default.js that allows all office type of files as those are needed in other places in project.
{
name: '_file',
type: 'joinByOne',
withType: 'apostrophe-file',
label: 'File',
required: true,
idField: 'fileId',
filters: {
projection: {
slug: 1,
title: 1,
attachment: 1
}
},
extensions: ['pdf'],
extensionMaps: {},
image: false
}
Can anyone help me on this please?

It sounds like you'll want to create a new file group in Apostrophe-attachments. You can use a file group to specify what types of files and/or extensions should be available when you add an apostrophe-attachments field to an object's schema. In order to add a file group that only contains PDFs, you will want to add this to the modules object in your app.js file:
'apostrophe-attachments': {
fileGroups: [
{
name: 'pdf',
label: 'Pdf',
extensions: ['pdf'],
image: false
}
]
}
This will create a new file group that will only allow files with the extension 'pdf'. Apostrophe-files isn't a regular schema type (it can't be added to an object's schema like other objects can). Instead of using apostrophe-files, it would be better to use apostrophe-attachments, which can be given a file group to restrict what types of files are allowed. In order to specify that group in your attachment, your new field will end up looking like this:
{
name: 'file',
type: 'attachment',
label: 'File',
group: 'pdf',
required: true
}
If you do decide you need to use a join directly to apostrophe-files, you will probably need to add some custom code in order to restrict the file type. If that is the case, you can find more information about apostrophe-files here:
https://apostrophecms.org/docs/modules/apostrophe-files/
You will probably be able to look at the way apostrophe-attachments handles file groups and replicate the behavior if necessary:
https://apostrophecms.org/docs/modules/apostrophe-attachments/

Related

save style for each field in database

I use mongodb and I have a model like this:
{
title: {
type: String,
required: true,
},
description: {
type: String,
required: true,
},
date: {
type: Date,
required: true,
},
}
I want to save styles (such as font, size, color, etc.) for each field
What is the best way to store them in a database?
Do I have to create a new field for each of them to store their style as a string (HTML code)?
You can create the list of css class like what bootstrap does. And then, you will create a new filed for each of them where you will just store the classes name.
all css will be stored in the css files
classes names associated to each elements will be stored in the database.
In that way, your app will be stay clean and you can reuse a lot of css class.

How to show uploaded image in Keystonejs back-end

Very similar to problem here but I'm not using S3 files and the info in that link is somewhat dated (hasn't been updated since github issues linked from question above were closed).
My question is about how to get a preview of an uploaded image in Keystonejs's admin back-end. Although it seems like it's a hacky fix (editing keystone files as suggested in link above) I'm wondering if there's other options.
Although they've added support for S3 files and Types.CloudinaryImage is supported I can't get a preview of the uploaded image when it's just an uploaded image since Keystone treats it as an arbitrary file (not an image).
Screenshot: as you can see Keystone just shows the filename (highlighted in red).
Model is set up as follows:
var keystone = require('keystone');
var Types = keystone.Field.Types;
/**
* Image Upload Model
* ==================
* A database model for uploading images to the local file system
*/
var ImageUpload = new keystone.List('ImageUpload');
var myStorage = new keystone.Storage({
adapter: keystone.Storage.Adapters.FS,
fs: {
path: keystone.expandPath('./public/uploads/images'),
publicPath: '/public/uploads/images',
}
});
ImageUpload.add({
name: { type: Types.Key, index: true },
image: {
type: Types.File,
storage: myStorage
},
createdTimeStamp: { type: String },
url: { type: String }
});
ImageUpload.defaultColumns = 'url, createdTimeStamp, image';
ImageUpload.register();
As far as I get it the only way - is to implement this by yourself.
It's not so scary as it my look but you should spend a lot of time to do that.
You need to investigate how for now different filed types are showed in admin page - for that you should take a look at template for admin page which is provided with KeystoneJS already (path: node_modules\keystone\admin\server\templates)
After that you might want to look for (path: node_modules\keystone\fields)
You might be interested in TYPES subfolder - cause there different field types rules
So your goal is to find corresponding field description (for your ImageUpload FileSystem model) or create a new one with img tag to show picture from url
I think File type is that what you are looking for - \node_modules\keystone\fields\types\file
Image previews are now possible in the latest master branch of keystone (see https://github.com/keystonejs/keystone/pull/4509). At the moment you need to depend on the git version of keystone, so put this in your package.json and run npm install:
"keystone": "https://github.com/keystonejs/keystone.git"
In your model, specify thumb: true on the image field in question. You also need the url property in the schema. For example:
const storage = new keystone.Storage({
adapter: keystone.Storage.Adapters.FS,
fs: {
path: keystone.expandPath('./uploads/images'),
publicPath: '/images/'
},
schema: {
url: true,
}
})
ImageUpload.add({
name: { type: Types.Key, index: true },
image: {
type: Types.File,
storage: myStorage,
thumb: true
},
createdTimeStamp: { type: String }
});
The admin UI should now show a small preview of the image and a link to it.

Execute query in Mongoose schema validation

Im trying to setup my MongoDB design in such a way that there is a projects collection, and a people collection. The Project model schema contains a _people item, which references the People model. (As opposed to the People model having a field to reference the project he/she belongs to. It needs to be like this)
I need to run a validation whenever a new document is created in the people container, that there can be only one manager per a project. This would be very easy if it was possible for me to execute a query for the elements validation in the schema, but I don't believe thats possible...
Heres the schema for the People model currently:
const peopleSchema = new Schema( {
name: {
type: Schema.Types.String,
required: true,
minlength: 3,
maxlength: 25,
trim: true,
select: true
},
isManager: {
type: Schema.Types.Boolean,
default: false,
validate: {
validator: function ( v ) {
// How can I check if there are any existing `people` documents with the
// `isManager` set to true, which are referenced by the same project.
// If I can return a promise from here, then I can just execute a query and verify the results
},
message: 'There can be only one manager per each group'
}
}
})
As you can see in the isManager.validate.validator function, I noted that if this documents isManager is set to true, I need to find a way to check that there isn't already a person document referenced by the same project that is also a manager.
Knowing which project is referencing this document isn't an issue, I will have that somewhere, I just need to know how to run a query.. is that possible?
I was able to accomplish the desired effect by using Mongooses Middleware functionality. Setting up the validation inside the pre-save hook worked just fine

KeystoneJS relationship type, limit available items by field value

Is it possible to limit available displayed options in a relationship type of KeystoneJS by specifying a value condition?
Basically, a model has two sets of array fields, instead of letting the admin user select any item from the field, I would like to restrict to only the items that are part of a specific collection _id.
Not sure if this is exactly the feature you're looking for, but you can specify a filter option on the Relationship field as an object and it will filter results so only those that match are displayed.
Each property in the filter object should either be a value to match in the related schema, or it can be a dynamic value matching the value of another path in the schema (you prefix the path with a :).
For example:
User Schema
User.add({
state: { type: Types.Select, options: 'enabled, disabled' }
});
Post Schema
// Only allow enabled users to be selected as the author
Post.add({
author: { type: Types.Relationship, ref: 'User', filter: { state: 'enabled' } }
});
Or for a dynamic example, imagine you have a role setting for both Posts and Users. You only want to match authors who have the same role as the post.
User Schema
User.add({
userRole: { type: Types.Select, options: 'frontEnd, backEnd' }
});
Post Schema
Post.add({
postRole: { type: Types.Select, options: 'frontEnd, backEnd' },
// only allow users with the same role value as the post to be selected
author: { type: Types.Relationship, ref: 'User', filter: { userRole: ':postRole' } }
});
Note that this isn't actually implemented as back-end validation, it is just implemented in the Admin UI. So it's more of a usability enhancement than a restriction.
To expand on Jed's answer, I think the correct property (at least in the latest version of KeystoneJS 0.2.22) is 'filters' instead of 'filter'. 'filter' doesn't work for me.

Sails.js & MongoDB: duplicate key error index

I'm using Sails.js (0.9.8) and MongoDB (via the sails-mongo adaptor) to create a collection of pages that can be positioned in a tree-view. I would like to store the path of a page in an array of UUIDs
My model:
module.exports = {
schema: true,
attributes: {
uuid: {
type: 'string',
unique: true,
required: true,
uuidv4: true
},
name: {
type: 'string',
required: true,
empty: false
},
path: {
type: 'array',
required: true,
array: true
}
}
}
It works well when I save a 'root' page (the 'path' property has just one item because it's a root page. Here is what it was saved in MongoDB:
{
_id: ObjectId("52f853e9609fb6c0341bdfcc"),
createdAt: ISODate("2014-02-10T04:22:01.828Z"),
name: "Home Page",
path: [
"a2b23e1f-954b-49a3-91f1-4d62d209a093"
],
updatedAt: ISODate("2014-02-10T04:22:01.833Z"),
uuid: "a2b23e1f-954b-49a3-91f1-4d62d209a093"
}
But when I want to create a 'subpage' below my previous created page (Home Page/Products), I get this error:
MongoError: E11000 duplicate key error index: cms-project.item.$path_1
dup key: { : "a2b23e1f-954b-49a3-91f1-4d62d209a093" }
Here is the data I sent:
{ name: 'Products',
uuid: 'a004ee54-7e42-49bf-976c-9bb93c118038',
path:
[ 'a2b23e1f-954b-49a3-91f1-4d62d209a093',
'a004ee54-7e42-49bf-976c-9bb93c118038' ] }
I probably missed something but I don't know what.
If I store the path in a string instead of an array, it work well, but I find it much less elegant and handy.
Not sure of all the Sails / Waterline parts myself as I've never played with it. But by the error the problem is there is a unique index on your array field.
When you are inserting your second document, you already have one of the values (the parent) in your path field in another document. The unique constraint is not going to allow this. Most certainly for what you are modelling, you do not want this and the index cannot be unique.
I hope that you set this up yourself under the assumption that it meant unique within the array contained in the document. If you did then you know where to look and what to change now. If this is being automatically deployed somehow, then I'm not the one to help.
Change the index to not be unique. You can confirm this through the mongo shell:
use cms-project
db.item.getIndices()
Good luck

Resources