好的, 让我们来详细规划第 11 部分: 扩展和集成。我们将这部分分为 3 天, 每天专注于特定的扩展和集成任务。

第 11 部分:扩展和集成 (3 天)

Day 1: 开发浏览器扩展

  1. 设置浏览器扩展项目结构 创建新的目录 browser-extension 并初始化:

    mkdir browser-extension
    cd browser-extension
    npm init -y
    npm install --save-dev webpack webpack-cli copy-webpack-plugin
  2. 创建 manifest 文件 在 browser-extension 目录下创建 manifest.json:

    {
      "manifest_version": 2,
      "name": "LightweightTodo Pro Extension",
      "version": "1.0",
      "description": "Quickly add todos from any webpage",
      "permissions": ["activeTab", "storage"],
      "browser_action": {
        "default_popup": "popup.html",
        "default_icon": {
          "16": "icon16.png",
          "48": "icon48.png",
          "128": "icon128.png"
        }
      },
      "icons": {
        "16": "icon16.png",
        "48": "icon48.png",
        "128": "icon128.png"
      }
    }
  3. 创建 popup 界面 在 browser-extension 目录下创建 popup.html:

    <!DOCTYPE html>
    <html>
      <head>
        <title>Add Todo</title>
      </head>
      <body>
        <form id="addTodoForm">
          <input type="text" id="todoTitle" placeholder="Todo title" required>
          <textarea id="todoDescription" placeholder="Description"></textarea>
          <button type="submit">Add Todo</button>
        </form>
        <script src="popup.js"></script>
      </body>
    </html>
  4. 实现 popup 逻辑 创建 browser-extension/src/popup.ts:

    document.addEventListener('DOMContentLoaded', () => {
      const form = document.getElementById('addTodoForm') as HTMLFormElement;
      const titleInput = document.getElementById('todoTitle') as HTMLInputElement;
      const descriptionInput = document.getElementById('todoDescription') as HTMLTextAreaElement;
     
      form.addEventListener('submit', async (e) => {
        e.preventDefault();
        const title = titleInput.value;
        const description = descriptionInput.value;
     
        try {
          const response = await fetch('https://api.lightweighttodo.com/todos', {
            method: 'POST',
            headers: {
              'Content-Type': 'application/json',
              'Authorization': 'Bearer ' + localStorage.getItem('token')
            },
            body: JSON.stringify({ title, description })
          });
     
          if (response.ok) {
            alert('Todo added successfully!');
            titleInput.value = '';
            descriptionInput.value = '';
          } else {
            throw new Error('Failed to add todo');
          }
        } catch (error) {
          alert('Error: ' + error.message);
        }
      });
    });
  5. 配置 webpack 创建 browser-extension/webpack.config.js:

    const path = require('path');
    const CopyPlugin = require('copy-webpack-plugin');
     
    module.exports = {
      entry: './src/popup.ts',
      output: {
        filename: 'popup.js',
        path: path.resolve(__dirname, 'dist'),
      },
      module: {
        rules: [
          {
            test: /\.ts$/,
            use: 'ts-loader',
            exclude: /node_modules/,
          },
        ],
      },
      resolve: {
        extensions: ['.ts', '.js'],
      },
      plugins: [
        new CopyPlugin({
          patterns: [
            { from: 'manifest.json', to: 'manifest.json' },
            { from: 'popup.html', to: 'popup.html' },
            { from: 'icons', to: 'icons' },
          ],
        }),
      ],
    };

Day 2: 开发公共 API

  1. 设计 API 端点 创建 api-design.md:

    # LightweightTodo Pro Public API
     
    Base URL: https://api.lightweighttodo.com/v1
     
    ## Authentication
    All requests must include an `Authorization` header with a valid API key.
     
    ## Endpoints
     
    ### List Todos
    GET /todos
     
    Query Parameters:
    - status: 'all' | 'active' | 'completed'
    - page: number
    - limit: number
     
    ### Get Todo
    GET /todos/:id
     
    ### Create Todo
    POST /todos
     
    Request Body:
    {
      "title": string,
      "description": string,
      "dueDate": string (ISO 8601 format),
      "tags": string[]
    }
     
    ### Update Todo
    PUT /todos/:id
     
    Request Body:
    {
      "title": string,
      "description": string,
      "dueDate": string (ISO 8601 format),
      "tags": string[],
      "status": 'active' | 'completed'
    }
     
    ### Delete Todo
    DELETE /todos/:id
     
    ### List Tags
    GET /tags
     
    ### Create Tag
    POST /tags
     
    Request Body:
    {
      "name": string
    }
     
    ### Delete Tag
    DELETE /tags/:id
  2. 实现 API 端点 在后端项目中创建新的控制器 PublicApiController.ts:

    import { Controller, Get, Post, Put, Delete, Body, Param, Query, UseGuards } from '@nestjs/common';
    import { ApiKeyGuard } from '../guards/api-key.guard';
    import { TodoService } from '../services/todo.service';
    import { TagService } from '../services/tag.service';
     
    @Controller('v1')
    @UseGuards(ApiKeyGuard)
    export class PublicApiController {
      constructor(
        private readonly todoService: TodoService,
        private readonly tagService: TagService
      ) {}
     
      @Get('todos')
      async listTodos(@Query() query) {
        return this.todoService.list(query);
      }
     
      @Get('todos/:id')
      async getTodo(@Param('id') id: string) {
        return this.todoService.get(id);
      }
     
      @Post('todos')
      async createTodo(@Body() todoData) {
        return this.todoService.create(todoData);
      }
     
      @Put('todos/:id')
      async updateTodo(@Param('id') id: string, @Body() todoData) {
        return this.todoService.update(id, todoData);
      }
     
      @Delete('todos/:id')
      async deleteTodo(@Param('id') id: string) {
        return this.todoService.delete(id);
      }
     
      @Get('tags')
      async listTags() {
        return this.tagService.list();
      }
     
      @Post('tags')
      async createTag(@Body() tagData) {
        return this.tagService.create(tagData);
      }
     
      @Delete('tags/:id')
      async deleteTag(@Param('id') id: string) {
        return this.tagService.delete(id);
      }
    }
  3. 实现 API 密钥认证 创建 src/guards/api-key.guard.ts:

    import { Injectable, CanActivate, ExecutionContext, UnauthorizedException } from '@nestjs/common';
    import { Observable } from 'rxjs';
     
    @Injectable()
    export class ApiKeyGuard implements CanActivate {
      canActivate(
        context: ExecutionContext,
      ): boolean | Promise<boolean> | Observable<boolean> {
        const request = context.switchToHttp().getRequest();
        const apiKey = request.get('Authorization');
     
        if (!apiKey) {
          throw new UnauthorizedException('API key is missing');
        }
     
        // In a real application, you would validate the API key against a database
        if (apiKey !== 'valid-api-key') {
          throw new UnauthorizedException('Invalid API key');
        }
     
        return true;
      }
    }
  4. 编写 API 文档 使用 Swagger 生成 API 文档。安装所需依赖:

    npm install --save @nestjs/swagger swagger-ui-express

    main.ts 中设置 Swagger:

    import { NestFactory } from '@nestjs/core';
    import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
    import { AppModule } from './app.module';
     
    async function bootstrap() {
      const app = await NestFactory.create(AppModule);
     
      const config = new DocumentBuilder()
        .setTitle('LightweightTodo Pro API')
        .setDescription('The LightweightTodo Pro API description')
        .setVersion('1.0')
        .addApiKey({ type: 'apiKey', name: 'Authorization', in: 'header' }, 'API-Key')
        .build();
      const document = SwaggerModule.createDocument(app, config);
      SwaggerModule.setup('api', app, document);
     
      await app.listen(3000);
    }
    bootstrap();

Day 3: 集成第三方服务

  1. 集成 Google Calendar 安装所需依赖:

    npm install googleapis

    创建 src/services/google-calendar.service.ts:

    import { Injectable } from '@nestjs/common';
    import { google } from 'googleapis';
     
    @Injectable()
    export class GoogleCalendarService {
      private calendar;
     
      constructor() {
        const auth = new google.auth.JWT(
          process.env.GOOGLE_CLIENT_EMAIL,
          null,
          process.env.GOOGLE_PRIVATE_KEY,
          ['https://www.googleapis.com/auth/calendar']
        );
     
        this.calendar = google.calendar({ version: 'v3', auth });
      }
     
      async addEvent(todo) {
        const event = {
          summary: todo.title,
          description: todo.description,
          start: {
            dateTime: todo.dueDate,
            timeZone: 'UTC',
          },
          end: {
            dateTime: todo.dueDate,
            timeZone: 'UTC',
          },
        };
     
        try {
          const response = await this.calendar.events.insert({
            calendarId: 'primary',
            resource: event,
          });
          return response.data;
        } catch (error) {
          console.error('Error adding event to Google Calendar:', error);
          throw error;
        }
      }
    }
  2. 集成 Slack 通知 安装所需依赖:

    npm install @slack/web-api

    创建 src/services/slack.service.ts:

    import { Injectable } from '@nestjs/common';
    import { WebClient } from '@slack/web-api';
     
    @Injectable()
    export class SlackService {
      private slack: WebClient;
     
      constructor() {
        this.slack = new WebClient(process.env.SLACK_BOT_TOKEN);
      }
     
      async sendNotification(message: string) {
        try {
          await this.slack.chat.postMessage({
            channel: process.env.SLACK_CHANNEL_ID,
            text: message,
          });
        } catch (error) {
          console.error('Error sending Slack notification:', error);
          throw error;
        }
      }
    }
  3. 实现集成逻辑 更新 TodoService 以使用新的集成服务:

    import { Injectable } from '@nestjs/common';
    import { GoogleCalendarService } from './google-calendar.service';
    import { SlackService } from './slack.service';
     
    @Injectable()
    export class TodoService {
      constructor(
        private readonly googleCalendarService: GoogleCalendarService,
        private readonly slackService: SlackService
      ) {}
     
      async create(todoData) {
        // 创建todo的逻辑...
     
        // 添加到Google Calendar
        await this.googleCalendarService.addEvent(createdTodo);
     
        // 发送Slack通知
        await this.slackService.sendNotification(`New todo created: ${createdTodo.title}`);
     
        return createdTodo;
      }
     
      // 其他方法...
    }
  4. 配置环境变量 更新 .env 文件:

    GOOGLE_CLIENT_EMAIL=your-google-client-email
    GOOGLE_PRIVATE_KEY=your-google-private-key
    SLACK_BOT_TOKEN=your-slack-bot-token
    SLACK_CHANNEL_ID=your-slack-channel-id
    
  5. 更新文档 在 README.md 中添加新的集成信息:

    ## Integrations
     
    ### Google Calendar
    LightweightTodo Pro now integrates with Google Calendar. When you create a todo with a due date, it will automatically be added to your Google Calendar.
     
    ### Slack Notifications
    Receive Slack notifications for important todo updates. Configure your Slack workspace and channel in the settings to enable this feature.
     
    ## API
    LightweightTodo Pro now offers a public API for developers. Check out our [API documentation](api-docs.md) for more information on how to integrate LightweightTodo Pro into your own applications.

这个详细计划涵盖了第 11 部分的扩展和集成, 包括开发浏览器扩展、创建公共 API, 以及集成第三方服务如 Google Calendar 和 Slack。通过这些步骤, LightweightTodo Pro 的功能得到了显著扩展, 为用户提供了更多的使用方式和集成选项。