Автор статей не отображается не вошедшим в систему пользователям в Apostrophe CMS

Я создал проект с использованием Apostrophe CMS и постоянно развиваю новые страницы и статьи. Содержимое (статьи и страницы), которые мы публикуем, будет доступно для всех (не вошедших в систему пользователей), а также для вошедших в систему пользователей (администраторов).

Я уже понимаю основы схемы в Apostrophe CMS и пытался отладить следующее поведение, тема этого вопроса: автор статей не показывается для не авторизованных пользователей.

Я не уверен, является ли это ошибкой или поведением по умолчанию, но мне действительно нужна некоторая помощь, поскольку я уже потратил несколько часов на поиск того, как это исправить / исправить.


Что я отлаживал до сих пор

  1. Вот как показан большой палец статьи для вошедшего в систему пользователя:

< залогиненный большой палец статьи>

  1. И вот как это показано для незарегистрированного пользователя:

< не залогиненный большой палец статьи>

Обратите внимание, что автор не отображается, если я не вошел в систему. Это часть HTML, которая отображает большой палец автора:

<div class="wrap-content">

  {% if piece._author.thumbnail.items.length %}
    <img src="{{apos.attachments.url(apos.images.first(piece._author.thumbnail))}}" class="image-user" alt="">
  {% endif %}

  <h2 class="title">{{piece.title}}</h2>
  <p class="description">{{ piece.description }} </p>
  1. Я узнал, чтоreq.userустановлен вpassportпакет, показанный на изображении ниже:

node_modules/passport/lib/strategies/session.js

< passport-set-req-user>

  1. Я пришел к одному условию "если", которое проверяет, вошел ли пользователь в систему. На изображении ниже я не вошел в систему, поэтомуreq.userне определено

node_modules/apostrophe/lib/modules/apostrophe-schemas/index.js

< apostrophe-cms-logged-off>

  1. И при входе в систему пользователь настраивается:

node_modules/apostrophe/lib/modules/apostrophe-schemas/index.js

< apostrophe-cms-залогинился>

  1. При входе в систему, апостроф-схемыjoinByOneи другие виды соединений. То, что я должен присоединиться, находится в:

lib/modules/apostrophe-blog/index.js

addFields: [
  {
    name: '_author',
    label: 'Author',
    type: 'joinByOne',
    withType: 'apostrophe-user',
    idField: 'userId',
  },

Где userId - это зарегистрированный идентификатор пользователя при создании статьи. Присоединяется как _author.

  1. В приведенном выше html-файле, если есть "piece._author", он показывает автора, в противном случае - нет. Не так, как мы никогда не присоединяемся, никогда не бывает автора, поэтому я не показываю автора, если я не вошел в систему.

Я уже пытался комментировать условие "если", без какого-либо эффекта, поэтому безуспешно (я мог видеть статьи в списке нормально, но без автора).

Нам действительно нужно показать автору всем.Как мне это сделать? Заранее спасибо.

2 ответа

Решение

Итак, с помощью @boutell и изучения документов я решил проблему.

Этот урок не слишком длинный и довольно простой.

обзор

  1. Создан новый profiles Тип куска - 1 профиль на пользователя.
  2. Каждый профиль имеет description поле (например, раздел "об авторе")
  3. каждый apostrophe-blog сущность имеет 1 _author (идентификатор профиля)
  4. Установите крючок для после вставки user создать и связать его profile,
  5. Установите крючок для перед вставкой apostrophe-blog s, чтобы связать profile зарегистрированного пользователя.
  6. Создать migration чтобы генерировать profile для каждого уже существующего user,
  7. Создайте migration поменять местами поля и значения в apostrophe-blog:
    • Узнав о проблеме, я уже имел userId поле в apostrophe-blog, Итак migration изменения от userId в userProfileId, значение которого говорит само за себя. Если у вас нет этого поля или нет apostrophe-blog Тем не менее, вам не понадобится эта миграция.

Версия модулей апостроф, которую я использовал, выглядит следующим образом:

"apostrophe": "^2.37.2",
"apostrophe-blog": "^2.1.1",

Решение

  1. Создан новый profiles штучный тип

/app.js

    modules: {
        'apostrophe-blog': {},
        'apostrophe-tags': {},
        'profiles': {}, // <-- add this
  1. Создайте папку и файл ниже:

/lib/modules/profiles/index.js

    /**
     * Module for adding "profile" entity. Every user has its profile. Before article (apostrophe-blog)
     * entities are inserted, they have the logged in user's profile id userprofile._id attached to
     * the article, as userProfileId field. This way, author of articles are always shown, even to
     * non-logged in users. In this file two migrations are included - add profile to existing
     * users and change from old "userId" that were in articles to new "userProfileId".
     * 
     * Run migration with node app.js apostrophe-migrations:migrate.
     * 
     * @author Alexandre Duarte (github.com/duartealexf)
     */

    const async = require('async');

    module.exports = {

        /**
         * Default stuff required by ApostropheCMS.
         */
        extend: 'apostrophe-pieces',
        name: 'profile',
        label: 'Profile',
        pluralLabel: 'Profiles',
        searchable: false,

        afterConstruct: function(self, callback) {

            /**
             * Ensure collection is set and add migrations to DB.
             */
            return async.series([
                self.ensureCollection,
                self.addUserProfileMigration,
                self.addBlogPageAuthorMigration,
            ], callback);
        },

        beforeConstruct: function(self, options) {

            options.addFields = [
                /**
                 * User of profile.
                 */
                {
                    name: '_user',
                    label: 'User',
                    type: 'joinByOne',
                    withType: 'apostrophe-user',
                    idField: 'userId',
                },

                /**
                 * Optional profile description.
                 */
                {
                    type: 'string',
                    textarea: true,
                    name: 'description',
                    label: 'Description',
                },

                /**
                 * Whether profile is published.
                 * Does not affect whether author is shown.
                 */
                {
                    type: 'boolean',
                    name: 'published',
                    label: 'Published',
                    def: true,
                },

                /**
                 * Profile thumbnail.
                 */
                {
                    name: 'thumbnail',
                    type: 'singleton',
                    widgetType: 'apostrophe-images',
                    label: 'Picture',
                    options: {
                        limit: 1,
                        aspectRatio: [100,100]
                    }
                }
            ].concat(options.addFields || []);
        },

        construct: function(self, options) {

            /**
             * Ensure collection variable is set.
             * 
             * @param {Function} callback 
             */
            self.ensureCollection = function(callback) {
                return self.apos.db.collection('aposDocs', function(err, collection) {
                    self.db = collection;
                    return callback(err);
                });
            };

            /**
             * Hook after inserting user. Actually watches on any doc insert,
             * so we need the 'if' statement below.
             *
             * @param {any} req Request.
             * @param {any} doc Doc being inserted.
             * @param {any} options Options from hook.
             * @param {any} callback
             */
            self.docAfterInsert = function(req, doc, options, callback) {

                /**
                 * No doc id, no change.
                 */
                if (!doc._id) {
                    return setImmediate(callback);
                }

                /**
                 * If it is an user, we add the profile.
                 */
                if (doc.type === 'apostrophe-user') {
                    return self.addUserProfile(req, doc, options, callback);
                }
                return setImmediate(callback);
            }

            /**
             * Hook before inserting article.
             * 
             * @param {any} req Request.
             * @param {any} doc Doc being inserted.
             * @param {any} options Options from hook.
             * @param {any} callback
             */
            self.docBeforeInsert = function(req, doc, options, callback) {

                /**
                 * No doc id, no change.
                 */
                if (!doc._id) {
                    return setImmediate(callback);
                }

                /**
                 * If it is a apostrophe-blog, we associate the profile
                 */
                if (doc.type === 'apostrophe-blog') {
                    return self.addProfileToArticle(req, doc, options, callback);
                }
                return setImmediate(callback);
            }

            /**
             * Method for creating user profile.
             * 
             * @param {any} req Request.
             * @param {any} user User having profile added.
             * @param {any} options Options from hook.
             * @param {any} callback
             */
            self.addUserProfile = function(req, user, options, callback) {

                /**
                 * Our profile entity.
                 */
                const profile = {
                    description: '',
                    published: true,
                    userId: user._id,
                    title: user.title,
                    slug: user.slug.replace(/^(user\-)?/, 'profile-'),
                    thumbnail: user.thumbnail
                }

                /**
                 * Insert async.
                 */
                return async.series({
                    save: function(callback) {
                        return self.insert(req, profile, {}, callback);
                    }
                });
            }

            /**
             * Method to add userProfileId to article.
             * 
             * @param {any} req Request.
             * @param {any} article Article having profile associated.
             * @param {any} options Options from hook.
             * @param {any} callback
             */
            self.addProfileToArticle = async function(req, article, options, callback) {

                /**
                 * Currently logged in user.
                 */
                const user = req.user;

                /**
                 * Extra check.
                 */
                if (!user) {
                    return setImmediate(callback);
                }

                /**
                 * This promise should resolve to the
                 * currently logged in user's profile id.
                 */
                const profileId = await new Promise(resolve => {

                    // Get profile of logged in user.
                    self.db.find({ type: self.name, userId: user._id }, async function(err, cursor) {
                        if (err) {
                            resolve();
                        }

                        const profile = await cursor.next();

                        resolve(profile ? profile._id : undefined);
                    });
                });

                /**
                 * No profile, no association.
                 */
                if (!profileId) {
                    return setImmediate(callback);
                }

                /**
                 * Attach the userProfileId and callback (ApostropheCMS will save the entity).
                 */
                article.userProfileId = profileId;

                return setImmediate(callback);
            }

            /**
             * Method to add migration that adds profile to already existing users.
             * 
             * @param {Function} callback 
             */
            self.addUserProfileMigration = function(callback) {

                /**
                 * Add migration to DB. The callback function will be called
                 * when running ApostropheCMS's CLI 'migration' command.
                 */
                self.apos.migrations.add(self.__meta.name + '.addUserProfile', function(callback) {

                    /**
                     * The users that need migrating.
                     */
                    let usersToMigrate = [];

                    /**
                     * Run 'docs' and 'migrate' functions async.
                     */
                    return async.series([ docs, migrate ], callback);

                    /**
                     * Get the users that need migrating.
                     */
                    function docs(callback) {

                        /**
                         * Get all profiles.
                         */
                        return self.db.find({ type: self.name }, async function(err, profiles) {
                            if (err) {
                                return callback(err);
                            }

                            let userIds = [], profile;

                            /**
                             * Fill array of userIds from already existing profiles.
                             */
                            while (profile = await profiles.next()) {
                                userIds.push(profile.userId);
                            }

                            /**
                             * Get all users not in userIds (users that have no profile).
                             * These are the usersToMigrate.
                             */
                            self.db.find({ type: 'apostrophe-user', _id: { $nin: userIds } }, async function(err, users) {
                                if (err) {
                                    return callback(err);
                                }

                                while (user = await users.next()) {
                                    usersToMigrate.push(user);
                                }

                                return callback(null);
                            });
                        })
                    }

                    /**
                     * Run migration.
                     * 
                     * @param {Function} callback 
                     */
                    async function migrate(callback) {

                        /**
                         * Iterate on usersToMigrate and create a profile for each user.
                         */
                        for (let i = 0; i < usersToMigrate.length; i++) {
                            const user = usersToMigrate[i];

                            /**
                             * Our profile entity.
                             */
                            const profile = {
                                _id: self.apos.utils.generateId(),
                                description: '',
                                published: true,
                                userId: user._id,
                                title: user.title,
                                type: self.name,
                                createdAt: user.updatedAt,
                                slug: user.slug.replace(/^(user\-)?/, 'profile-'),
                                docPermissions: [],
                                thumbnail: user.thumbnail,
                            }

                            await new Promise(resolve => self.db.insert(profile, resolve));
                        }

                        return setImmediate(callback);
                    }
                }, {
                    safe: true
                });

                return setImmediate(callback);

            }


            /**
             * Migration to swap from userId to userProfileId to
             * already existing apostrophe-blog entities.
             */
            self.addBlogPageAuthorMigration = function(callback) {

                /**
                 * Add migration to DB. The callback function will be called
                 * when running ApostropheCMS's CLI 'migration' command.
                 */
                self.apos.migrations.add(self.__meta.name + '.addBlogPageAuthor', function(callback) {

                    /**
                     * Mapping of profile id by user id.
                     */
                    const profileMapByUserId = new Map();

                    /**
                     * Posts (apostrophe-blog entities) that need migrating.
                     */
                    const postsToMigrate = [];

                    /**
                     * Run 'posts', 'profiles' and 'migrate' functions async.
                     */
                    return async.series([ posts, profiles, migrate ], callback);

                    /**
                     * Get the posts that need migrating.
                     * 
                     * @param {Function} callback
                     */
                    function posts(callback) {

                        /**
                         * Get all posts having an userId set (not yet migrated ones).
                         */
                        return self.db.find({ type: 'apostrophe-blog', userId: { $exists: true }}, async function(err, blogPosts) {
                            if (err) {
                                return callback(err);
                            }

                            let post;

                            /**
                             * Add found posts to postsToMigrate.
                             */
                            while (post = await blogPosts.next()) {
                                postsToMigrate.push(post);
                            }

                            return callback(null);
                        });
                    }

                    /**
                    * Create the profiles mapping by user id.
                    * 
                    * @param {Function} callback
                    */
                    function profiles(callback) {

                        /**
                        * As this function is running async, we need to set immediate
                        * callback to not migrate if there are no posts to migrate.
                        */
                        if (!postsToMigrate.length) {
                            setImmediate(callback);
                        }

                        /**
                        * Get all profiles.
                        */
                        return self.db.find({ type: self.name }, async function(err, profiles) {
                            if (err) {
                                return callback(err);
                            }

                            let profile;

                            /**
                            * Build mapping.
                            */
                            while (profile = await profiles.next()) {
                                profileMapByUserId.set(profile.userId, profile);
                            }

                            return callback(null);
                        });
                    }

                    /**
                    * Run migration.
                    * 
                    * @param {Function} callback 
                    */
                    async function migrate(callback) {

                        let userId, profile, post;

                        for (let i = 0; i < postsToMigrate.length; i++) {

                            /**
                            * Get userId of post.
                            */
                            post = postsToMigrate[i];
                            userId = post.userId;

                            if (!userId) {
                                continue;
                            }

                            /**
                            * Get profile of user.
                            */
                            profile = profileMapByUserId.get(userId);

                            if (!profile) {
                                continue;
                            }

                            /**
                            * Swap from userId to userProfileId.
                            */
                            delete post.userId;
                            post.userProfileId = profile._id;

                            /**
                            * Replace the post to the new one having userProfileId.
                            */
                            await new Promise(resolve => self.db.replaceOne({ _id: post._id }, post, resolve));
                        }

                        return callback(null);
                    }
                }, {
                    safe: true
                });

                return setImmediate(callback);

            }
        }
    }

Примечание: файл выше содержит миграцию, которая предполагает, что у вас уже есть userId поле в apostrophe-blog юридические лица. Опять же, если у вас нет этого поля или еще нет блогов-апострофов, эта миграция вам не понадобится. Также предполагается, что у вас есть миниатюра для пользователей.

Код хорошо документирован, так что вы знаете, где изменить, если это необходимо.

  1. Добавить поле _author к apostrophe-blog удалите поле userId, если оно у вас есть (его безопасно удалить до миграции).

/lib/modules/apostrophe-blog/index.js

    module.exports = {

      addFields: [
        {                           // <-- add this
          name: '_author',          // <-- add this
          label: 'Author',          // <-- add this
          type: 'joinByOne',        // <-- add this
          withType: 'profile',      // <-- add this
          idField: 'userProfileId'  // <-- add this
        }                           // <-- add this
        // ...
      ],
      beforeConstruct: function(self, options) {
        // ...
  1. Запустите / перезапустите процесс ApostropheCMS, чтобы добавить миграцию.
  2. Запустите миграцию в CLI (не могу вспомнить, нужно ли вам для этого запускать ApostropheCMS).

Из корневой папки проекта:

node app.js apostrophe-migrations:migrate

  1. Внесите необходимые изменения в свой html файлы для отображения имени автора и эскиза, если применимо.

Вуаля! Теперь вы сможете увидеть автора.

Примечание. В этом руководстве не делается никаких заметок о том, нужно ли запускать ваше приложение 100% времени. В конечном итоге вам нужно будет снять его / перезапустить, чтобы добавить миграцию. Сначала запустите ваши тесты в среде разработки.

Вы не указываете, но так как apostrophe-blog не имеет _author присоединиться по умолчанию, я предполагаю, что вы добавили один, и что он присоединяется с apostrophe-user,

В Apostrophe 0.5 "пользователи" (которые могут делать что-то на сайте) и "люди" (о которых говорят на сайте, в каталогах публичной информации о сотрудниках и т. Д.) Были одинакового типа. В 2.x мы перестали это делать, потому что слишком часто встречается "автор", который на самом деле не является пользователем, или пользователь, чья информация никогда не должна показываться широкой публике.

Так в 2.х apostrophe-users никогда не устанавливает published флаг и не администраторы просто не могут найти других пользователей; публика вообще не может найти пользователей.

Мы рекомендуем создать profiles тип части вместо этого, и присоединение с этим. Это позволяет вам поддерживать разделение между "кто может что-то делать с сайтом" и "что публика знает о том, кто что-то написал".

Вы можете создавать профили автоматически, используя beforeSave обработчик для apostrophe-users,

Другие вопросы по тегам