Как создать простой плагин Strapi

Автор: Атх Трипатхи

Плагины Strapi существуют для того, чтобы облегчить нашу работу и сделать наш бэкенд более функциональным. Плагины удобны, и вы можете приобрести их на рынке Strapi, но иногда вам понадобятся некоторые пользовательские функции для бэкенда Strapi. Поэтому мы научимся создавать собственные плагины. Мы создадим простое приложение для напоминаний, которое будет отправлять электронное письмо всякий раз, когда вы добавляете напоминание. Давайте приступим.

Необходимые условия

  • Базовые знания Javascript
  • Базовые знания React
  • Базовое понимание Strapi
  • В системе должен быть установлен node.js.

Что такое Strapi?

В документации по Strapi говорится, что «Strapi — это безголовая CMS с открытым исходным кодом, которая дает разработчикам свободу выбора своих любимых инструментов и фреймворков, а редакторам — возможность управлять и распространять свой контент с помощью панели администратора приложения». Через админ-панель вы можете создавать функциональные плагины.

Создание проекта Strapi

Вы можете прочитать документацию по Strapi, где подробно описывается создание проекта с использованием CLI. Для этого проекта мы создадим проект быстрого запуска с базой данных SQLite, так как с нее легко начать. Однако вы можете использовать любую базу данных. Выполните приведенную ниже команду:

    npx create-strapi-app@latest tutorialdev --quickstart
Войти в полноэкранный режим Выйти из полноэкранного режима

Это создаст проект Srapi с именем «tutorialdev»; вы можете заменить его на любое имя.

Чтобы запустить проект, выполните приведенную ниже команду:

    npm run develop -- --watch-admin
Войти в полноэкранный режим Выйти из полноэкранного режима

Это запустит ваш strapi сервер на http://localhost:8000/.

Создание файлов плагинов с помощью CLI

Для создания основных файлов плагинов мы воспользуемся командой strapi CLI, которая очень проста.

Выполните эту команду:

npm run strapi generate
Войти в полноэкранный режим Выйти из полноэкранного режима

Затем выберите плагин и назовите его так, как вам нравится. Я назвал его «reminderapp». В вашем терминале появится код, подобный этому:

module.exports = {
  // ...
  reminderapp: {
    enabled: true,
    resolve: './src/plugins/reminderapp
  },
  // ...
}
Войти в полноэкранный режим Выйти из полноэкранного режима

Теперь перейдите в папку config в основном каталоге и найдите файл plugins.js. Если вы не можете найти этот файл, создайте его и вставьте приведенный выше код. Измените reminderapp на название плагина, который вы поставили, или просто скопируйте код из терминала и вставьте его.

Структура проекта

Давайте разберемся в базовой структуре нашего проекта и в том, какие файлы для нас важны. В вашей папке «src» вы сможете найти папку «plugins», внутри которой вы найдете папку с названием созданного вами плагина.

В нашем случае мы найдем «reminderapp». В ней есть две папки с названиями «admin» и «server». В основном вы будете работать в папке admin; открыв ее, вы увидите папку «pages», внутри которой находится папка «Homepage», где будет находиться фронтенд вашего плагина.

В папке «server» вы найдете контроллеры, маршруты, content-type, контроллеры и сервисы. Надеюсь, вы знакомы со всей терминологией. Мы будем использовать content-type для хранения напоминаний, а остальные три — для дополнительных функций. Давайте приступим к созданию бэкенда для таких плагинов, как content-type, сервисы для запроса данных, контроллеры, маршруты и другие вещи.

Создание Content-Type для сохранения напоминаний

Тип содержимого — это как схема для нашей базы данных; мы создадим тип содержимого для напоминаний.

Выполните эту команду:

    npm run strapi generate
Войти в полноэкранный режим Выйти из полноэкранного режима

Здесь выберите content-type. Введите название типа содержимого, который вы хотите создать, и продолжайте нажимать enter, ниже приведен пример того, как все будет выглядеть:

Добавьте атрибуты, которые вы хотите использовать в вашей схеме, их имена и тип данных. Когда вы закончите с их добавлением, выберите «Добавить модель в существующий плагин» и выберите имя нашего плагина. На картинке я использовал «todo», но вы должны использовать «reminder», так как картинка приведена только в качестве примера.

Будет сгенерирован файл schema.json; вы можете найти его, зайдя в папку plugins, затем в папку вашего сервера. Перейдите к content type, там вы увидите сгенерированную папку с именем типа контента, который вы указали, и внутри нее вы найдете schema.json.

В этом руководстве вы будете использовать четыре атрибута: name, date, datetime и isdatepassed. Теперь перейдем к созданию маршрутов, контроллеров и сервисов.

Создание маршрутов, контроллеров и сервисов

Маршруты — это конечные точки API, к которым мы будем обращаться. Сервисы относятся к тому, где мы будем писать весь код для запроса данных и других операций с базой данных. Контроллеры будут связывать их.

Давайте сначала создадим сервисы:

  • Перейдите в корневую папку плагина,
  • Перейдите в папку server/services,
  • Создайте файл с именем «reminder.js», и
  • Поместите в него этот код:
'use strict';
module.exports = ({ strapi }) => ({
 async getall(query){
  strapi.db.query('plugin::reminderapp.reminder').updateMany({
    where:{
      datetime:{
        $lt:new Date()
      }
    },
    data:{
      isdatepassed:true
    }
  })
    const q=strapi.entityService.findMany("plugin::reminderapp.reminder",{
      filters:{
        isdatepassed:{
          $eq:false
        }
      }
    });
    return await q;
 } ,
  async deleteReminder(id) {
    return await strapi.entityService.delete("plugin::reminderapp.reminder", id);
  },

  async createReminder(data) {
    return await strapi.entityService.create("plugin::reminderapp.reminder", data);
  },

  async updateReminder(id, data) {
    return await strapi.entityService.update("plugin::reminderapp.reminder", id, data);
  },
});
Войти в полноэкранный режим Выход из полноэкранного режима

Давайте разберемся, что здесь делает каждая функция.

  • getall(): Эта функция сначала обновляет атрибут «isdatepassed» всех напоминаний, чья дата уже прошла, затем выполняет запрос, чтобы вернуть все напоминания, чей атрибут isdatepassed равен false.
  • DeleteReminder(): Возьмет id напоминания и удалит его.
  • CreateReminder(): Создаст новый экземпляр напоминания с указанными вами данными.
  • UpdateReminder(): Обновляет напоминание, чей id вы передали, с заданными данными.

Теперь перейдите в папку server/controllers, создайте там файл reminder.js и добавьте в него следующее:

'use strict';

module.exports={
    async getall(ctx){
        try{
            return await strapi.plugin("reminderapp").service("reminder").getall(ctx.query);
        }
        catch(err){
            ctx.trow(500,err);
        }
    },

    async deleteReminder(ctx) {
      try {
        ctx.body = await strapi
          .plugin("reminderapp").service("reminder")
          .deleteReminder(ctx.params.id);
      } catch (err) {
        ctx.throw(500, err);
      }
    },
    async createReminder(ctx) {
      try {
        ctx.body = await strapi
          .plugin("reminderapp").service("reminder")
          .createReminder(ctx.request.body);
      } catch (err) {
        ctx.throw(500, err);
      }
    },

    async updateReminder(ctx) {
      try {
        ctx.body = await strapi
          .plugin("reminderapp").service("reminder")
          .updateReminder(ctx.params.id, ctx.request.body);
      } catch (err) {
        ctx.throw(500, err);
      }
    },
};
Войти в полноэкранный режим Выйти из полноэкранного режима

Здесь мы просто сделали наши сервисы доступными для наших маршрутов. Плагин принимает имя плагина, чьи сервисы мы собираемся использовать, а service() принимает имя сервиса, к которому мы собираемся получить доступ.

Теперь перейдите к файлу index.js в папке controllers:

'use strict';

const myController = require('./my-controller');
const reminder =require('./reminder');

module.exports = {
  myController,
  reminder,
};
Войти в полноэкранный режим Выйти из полноэкранного режима

Теперь перейдите в index.js в папке routes и добавьте следующий код:

module.exports = [
  {
    method: 'GET',
    path: '/',
    handler: 'myController.index',
    config: {
      policies: [],
    },
  },
  {
    method: 'GET',
    path: '/getall',
    handler: 'reminder.getall',
    config: {
      policies: [],
      auth:false,
    },
  },
  {
    method: "POST",
    path: "/create",
    handler: "reminder.createReminder",
    config: {
      policies: [],
    },
  },

  {
    method: "DELETE",
    path: "/delete/:id",
    handler: "reminder.deleteReminder",
    config: {
      policies: [],
    },
  },
  {
    method: "PUT",
    path: "/update/:id",
    handler: "reminder.updateReminder",
    config: {
      policies: [],
    },
  },
];
Войти в полноэкранный режим Выйти из полноэкранного режима

Это создаст маршруты для вашего фронтенда для доступа к сервисам плагина, которые мы создали. Теперь перейдите в корневую папку плагина, затем в admin/src и в папку API. Затем создайте файл с именем «reminder.js».

Добавьте в файл этот код:

import { request } from "@strapi/helper-plugin";
const ReminderApiHandler = {
  getAllReminders: async () => {
    return await request("/reminderapp/getall", {
      method: "GET",
    });
  },
  addReminder: async (data) => {
    return await request(`/reminderapp/create`, {
      method: "POST",
      body: { data: data },
    });
  },
  editReminder: async (id, data) => {
    return await request(`/reminderapp/update/${id}`, {
      method: "PUT",
      body: { data: data },
    });
  },
  deleteReminder: async (id) => {
    return await request(`/reminderapp/delete/${id}`, {
      method: "DELETE",
    });
  },
};
export default ReminderApiHandler;
Войти в полноэкранный режим Выйти из полноэкранного режима

Таким образом, вы сможете легко отправлять запросы к бэкенду Strapi из фронтенда вашего плагина. Вы закончили с настройкой бэкенда и установкой связи между фронтендом и бэкендом.

Давайте приступим к созданию фронтенда для нашего плагина.

Разработка фронтенда для плагина

Создание фронтенда для плагина — это следующая задача нашей разработки; это будет самая простая часть нашего проекта. Есть два способа создания фронтенда для плагина: создание CSS-файлов и их применение или использование стандартных таблиц стилей Strapi.

Мы будем использовать стандартные таблицы стилей Strapi. Нажмите здесь, чтобы посмотреть систему оформления Strapi. Изучите весь сборник рассказов и найдите удивительные стилизованные компоненты. Самое приятное, что он соответствует стилю по умолчанию в панели администратора Strapi, так что вам не нужно беспокоиться о темах.

Давайте приступим.

Домашняя страница

import React, { memo } from 'react';
// import PropTypes from 'prop-types';
import { Layout,BaseHeaderLayout } from '@strapi/design-system/Layout';
import { Button } from '@strapi/design-system/Button';
import Plus from '@strapi/icons/Plus';
import { Box } from '@strapi/design-system/Box';
import { EmptyStateLayout } from '@strapi/design-system/EmptyStateLayout';
import Calendar from '@strapi/icons/Calendar';
import { Table, Thead, Tbody, Tr, Td, Th } from '@strapi/design-system/Table';
import { Typography } from '@strapi/design-system/Typography';
import { DatePicker } from '@strapi/design-system/DatePicker';
import Modal from '../../components/Modal';
import ReminderApiHandler from '../../api/reminder';
import { Flex } from '@strapi/design-system/Flex';
import { IconButton } from '@strapi/design-system/IconButton';
import Pencil from '@strapi/icons/Pencil';
import Trash from '@strapi/icons/Trash';
import EditModal from '../../components/EditModal';
function HomePage(){

  const [reminderList,setReminder]=React.useState([]);  
const [ModalVisible,SetModalVisible]=React.useState(false);
  const [isEdit,setIsEdit]=React.useState(false)
  const [editedVal,setEditedVal]=React.useState({})
async function FetchReminders(){
  const reminders=await ReminderApiHandler.getAllReminders();
  setReminder(reminders)
}

async function DeleteReminders(id){
  const deleted=await ReminderApiHandler.deleteReminder(id)
  FetchReminders()
}

async function updateReminder(id,data){
  await ReminderApiHandler.editReminder(id,{"remindername":data.remindername,"date":data.date,'datetime':new Date(data.date)})
  FetchReminders()
}

function addReminder(data){
  ReminderApiHandler.addReminder({"remindername":data.remindername,"date":data.date,"datetime":new Date(data.date),"isdatepassed":false})
FetchReminders()
}


React.useEffect(()=>{
  FetchReminders()
},[])
  return (<Box>
      <Layout>

<Box background="neutral100">
<BaseHeaderLayout primaryAction={<Button startIcon={<Plus />} onClick={SetModalVisible}>Add an reminder</Button>}
 title="Add reminder" subtitle={`${reminderList.length} reminders found`} as="h2" />
    </Box>
    {reminderList.length==0?
    <Box padding={8} background="neutral100">
      <EmptyStateLayout icon={<Calendar />} content="You don't have any reminders yet..." />
    </Box>:
    <Table>
      <Thead>
        <Tr>
        <Th>
            <Typography variant="sigma">ID</Typography>
                </Th>
                <Th>
                  <Typography variant="sigma">Reminder name</Typography>
                </Th>
                <Th>
                  <Typography variant="sigma">date</Typography>
                </Th>

        </Tr>
      </Thead>
      <Tbody>
      {reminderList.map((k)=>{
      return(
      <Tr>
      <Td>
      <Typography textColor="neutral800">{k.id}</Typography>
    </Td>
    <Td>
      <Typography textColor="neutral800">{k.remindername}</Typography>
    </Td>
    <Td>
    <DatePicker selectedDate={new Date(k.date)} label="date" name="datepicker" selectedDateLabel={formattedDate => `Date picker, current is ${formattedDate}`} disabled />

    </Td>
    <Flex>
       <IconButton onClick={() => {
        setEditedVal({
          id:k.id,
          date:k.date,
          remindername:k.remindername
        })
        setIsEdit(true)
       }} label="Edit" noBorder icon={<Pencil />} />
      <Box paddingLeft={1}>
        <IconButton onClick={() => DeleteReminders(k.id)} label="Delete" noBorder icon={<Trash />} />
      </Box>
    </Flex>
    </Tr>

    )}
    )}
    </Tbody>
    </Table>}
      </Layout>
      {ModalVisible&& <Modal setShowModal={SetModalVisible} addReminder={addReminder}/>}
      {isEdit&& <EditModal setShowModal={setIsEdit} updateReminder={updateReminder} id={editedVal.id} dateGiven={editedVal.date} nameGiven={editedVal.remindername}/>}
    </Box>
    )
};
export default memo(HomePage);
Вход в полноэкранный режим Выход из полноэкранного режима

Этот фронтенд просто вызывает все напоминания из конечной точки getall. При нажатии на кнопку «добавить напоминание» откроется модальное окно, из которого вы сможете добавить напоминание. Нажав на иконку корзины, вы сможете удалить напоминание. При нажатии на кнопку «редактировать» откроется новый модальный экран, в котором будет открыто напоминание, значение которого вы редактируете.

В результате:

На пустом месте появится список напоминаний. У нас нет напоминаний, поэтому сейчас мы их не увидим, но как только они появятся. Мы сможем их увидеть.

Сейчас я покажу вам, как это будет выглядеть:

Отправка писем при создании напоминания

Перейдите в admin/src/api и создайте Mailer.js. Сначала загрузите библиотеку nodemailer с помощью следующей команды:

npm i nodemailer --save
Войдите в полноэкранный режим Выйти из полноэкранного режима

Теперь перейдите в файл и поместите этот код:

/*
    Video: https://www.youtube.com/watch?v=Va9UKGs1bwI
    Don't forget to disable less secure app from Gmail: https://myaccount.google.com/lesssecureapps TODO:
*/

const nodemailer = require('nodemailer');
const log = console.log;


\Step 1
const mail=’mailer@gmail.com'
const mailTo='mailto@gmail.com'
const password=’password'
let transporter = nodemailer.createTransport({
    service: 'gmail',
    auth: {
        user:mail, // TODO: your gmail account
        pass:password// TODO: your gmail password
    }
});

// Step 2
let mailOptions = {
    from: mail, // TODO: email sender
    to: mailTo, // TODO: email receiver
    subject: 'Reminder added',
    text: 'reminder'
};

// Step 3
Export default function Mailing(){
transporter.sendMail(mailOptions, (err, data) => {
    if (err) {
        return log('Error occurs'+err);
    }
    return log('Email sent!!!');
});
}
Войти в полноэкранный режим Выйти из полноэкранного режима

Для паролей

Перейдите в раздел Мой аккаунт > Вход & Безопасность > Пароли приложений, прокрутите вниз, выберите приложение и выберите «Другое». Назовите приложение «nodemailer», нажмите сгенерировать и скопируйте-вставьте длинный сгенерированный пароль в качестве пароля gmail.

Теперь перейдите в api/reminder.js и импортируйте вышеуказанную функцию и вызовите ее в функции create:

import SendingMail from './Mailer'
…..
  addReminder: async (data) => {
    SendingMail()
    return await request(`/reminderapp/create`, {
      method: "POST",
      body: { data: data },
    });
  },
….
Вход в полноэкранный режим Выйти из полноэкранного режима

Теперь вы закончили с созданием всего. Надеюсь, теперь вы поняли, как легко делать плагины для страпинга и как можно сделать их функциональными, используя сторонние пакеты.

Вот результат:

Заключение

  • Вы узнали, как делать плагины Strapi.
  • Вы узнали, как устроен проект в Strapi.
  • Как настроить маршруты, контроллеры и сервисы для создания бэкенда.
  • Как установить связь между фронтендом и бэкендом плагина.
  • Как сохранять напоминания с помощью типа контента и создавать схему с помощью типов контента.

Надеюсь, вы используете свои знания и сделаете классный плагин, который действительно поможет другим разработчикам Strapi и поможет сообществу Strapi.

Оцените статью
devanswers.ru
Добавить комментарий