将createdBy字段添加到keystone.js中的User模型

时间:2014-07-24 00:21:12

标签: node.js mongoose keystonejs

我将'createdBy'字段添加到模型中,但它允许管理员选择所有用户作为'createdBy'用户。我希望使用当前登录的管理员自动填充此字段,但似乎无法使其工作。

理想情况下,这根本不会出现在用户界面中,只是在保存用户时存储。

User.add({
    name: { type: Types.Name, required: true, index: true },
    email: { type: Types.Email, initial: true, required: true, index: true },
    company: { type: String, required: true, index: true, initial: true },
    phone: { type: String, required: true, index: true, initial: true },
    password: { type: Types.Password, initial: true, required: true },
    createdBy: { type: Types.Relationship, initial:true, required:true, ref: 'User' },
    createdAt: { type: Date, default: Date.now }
    }, 'Permissions', {
      level : { type: Types.Select, numeric: true, options: [{ value: 1, label: 'User'   }, {     value: 2, label: 'Group Administrator' }, { value: 3, label: 'System Administrator' }] }
    },
    'Screening', {
      rooms : { type: Types.Select, numeric: true, options: [{ value: 1, label: 'Screening room 1' }, { value: 2, label: 'Screening room 2' }, { value: 3, label: 'Screening room 3' }] }
});

2 个答案:

答案 0 :(得分:2)

虽然您的实施功能正常,但许多Keystone开发人员(包括我自己)对通过user.id发送POST的安全风险提出了疑虑。当你说目前在Keystone没有好办法的时候,你也是对的。

我的解决方案是在Keystone上实现该功能。我添加了一个可选的元模式,我称之为audit meta。这会在ListcreatedByupdatedBy)中添加两个字段,我使用现有的UpdateHandler()缓存副本填充req.user。这样就不需要通过POST发送user._id

要使用它,您只需在定义列表后添加List.addPattern('audit meta');,就像使用standard meta时一样。我对audit meta的实施也添加了standard meta字段,因此无需同时使用这两个字段。

为了实现这一点,我对Keystone进行了以下更改

首先,在lib\list.js中,我将以下代码(前缀为+)添加到addPatern()方法中:

List.prototype.addPattern = function(pattern) {

    switch (pattern) {
        ...

+       case 'audit meta':
+           var userModel = keystone.get('user model');
+
+           if(!this.schema.path('createdOn') && !this.schema.path('updatedOn')) {
+               this.addPattern('standard meta');
+           }
+
+           if (userModel) {
+               this.add({
+                   createdBy: { type: Field.Types.Relationship, ref: userModel, hidden: true, index: true },
+                   updatedBy: { type: Field.Types.Relationship, ref: userModel, hidden: true, index: true }
+               });
+               this.map('createdBy', 'createdBy');
+               this.map('modifiedBy', 'updatedBy');
+           }
+       break;
+
    }

    return this;

然后在lib/updateHandler.js我将以下代码添加到UpdateHandler.prototype.process(),就在方法结束时调用progress()之前。

+   // check for audit meta fields (mapped to createdBy/modifiedBy)
+   if (this.list.mappings.createdBy && this.item.isNew) {
+       this.item.set(this.list.mappings.createdBy, this.user._id);
+   }
+   if (this.list.mappings.modifiedBy) {
+       this.item.set(this.list.mappings.modifiedBy, this.user._id);
+   }

之前我向Keystone提交了拉取请求(https://github.com/JedWatson/keystone/pull/490),其中包含对我的实施的详细说明。所以,如果你迫切需要这个,你总是可以分叉一份Keystone并合并我的PR。

答案 1 :(得分:1)

显然没有好方法可以做到这一点,但我确实想出了一个通过创建自定义隐藏输入字段来使用别人的想法的工作。它并不理想,但适合这个项目。 createdBy上的默认值是这样我可以使它成为必填字段,但它填充在jade模板中,而不是该输入类型的初始jade模板。

User.add({
  name: { type: Types.Name, required: true, index: true },
  email: { type: Types.Email, initial: true, required: true, index: true },
  company: { type: String, required: true, index: true, initial: true },
  phone: { type: String, required: true, index: true, initial: true },
  password: { type: Types.Password, initial: true, required: true },
  createdBy: { type: Types.Admin, required: true, initial: true, default: 'createdBy' },
  createdAt: { type: Types.Hidden, default: Date.now }
}, 'Permissions', {
  level : { type: Types.Select, numeric: true, options: [{ value: 1, label: 'User' }, {     value: 2, label: 'Group Administrator' }, { value: 3, label: 'System Administrator' }] }
},Screening', {
  rooms : { type: Types.Select, numeric: true, options: [{ value: 1, label: 'Screening room 1' }, { value: 2, label: 'Screening room 2' }, { value: 3, label: 'Screening room 3' }] }
});

然后自定义字段类型就像这样,只需为表单和初始创建一个。还要创建fieldTypes / admin.js并更新fieldTypes.index.js

输入admin / form.jade

.field(class='type-' + field.type, data-field-type=field.type, data-field-path=field.path, data-field-collapse=field.collapse ? 'true' : false, data-field-depends-on=field.dependsOn, data-field-noedit=field.noedit ? 'true' : 'false')
- var value = field.format(item)
.field-ui(class='width-' + field.width)
    if field.noedit
        .field-value= user._id
    else
        input(type='hidden', name=field.path, value=user._id, autocomplete='off').form-control
    if field.note
        .field-note!= field.note