# 機能設計書 70-購読者インポート

## 概要

本ドキュメントは、QuickerSite CMSの管理画面におけるニュースレター購読者インポート機能の設計を定義する。

### 本機能の処理概要

購読者インポート機能は、外部からのメールアドレスリストを一括でニュースレター購読者として登録する機能である。

**業務上の目的・背景**：ニュースレター配信において、既存の顧客リストやメールリストから購読者を一括登録する必要がある。本機能は、テキストデータ（改行区切りのメールアドレスリスト、またはCSV形式の名前・メールアドレスペア）から有効なメールアドレスを抽出し、指定されたメールリスト（カテゴリ）に購読者として登録する。また、任意のテキストやHTMLからメールアドレスを自動抽出する機能も提供する。

**機能の利用シーン**：
- 既存の顧客リストからの購読者一括登録
- CSV形式のメールリストのインポート
- 名刺管理ソフトからのエクスポートデータの取り込み
- Webページ等からのメールアドレス抽出と登録
- 複数のメールリスト（カテゴリ）への同時登録

**主要な処理内容**：
1. インポート形式の選択（メールアドレスのみ、または名前+メールアドレス）
2. 対象メールリスト（カテゴリ）の選択（複数選択可）
3. メールアドレスの有効性検証
4. 重複チェック（既存登録との照合）
5. 新規購読者レコードの一括作成
6. 任意テキストからのメールアドレス抽出機能

**関連システム・外部連携**：特になし（CMS内部機能）

**権限による制御**：セカンドアドミン権限のbNewsletterフラグおよびbCanImportSubscribers（カテゴリ存在）条件によりアクセス制御される。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 70 | 購読者インポート | 主画面 | 購読者の一括インポート |
| 69 | 購読者管理 | 参照画面 | Subscribersリンク |
| 67 | ニュースレター一覧 | 参照画面 | Newsletter homeリンク |

## 機能種別

一括データインポート / データ抽出

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| importType | String | No | インポート形式（0=名前,メール、1=メールのみ） | "0"または"1"、デフォルト"1" |
| pairs | Text | No | インポートデータ（改行区切り） | - |
| cat | Array | Yes | 対象カテゴリID配列 | 複数選択チェックボックス |
| bimportinactive | Boolean | No | 無効状態でインポートフラグ | true/false |
| btnaction | String | Yes | アクション（Import/Extract） | "Import"または"Extract valid email addresses" |

### 入力データソース

- 画面入力フォーム（テキストエリア）
- データベーステーブル: tblNewsletterCategory（カテゴリ情報）
- セッション: 顧客ID（cId）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| sCounter | Integer | 登録成功件数 |
| 成功メッセージ | HTML | 「X subscriptions were added」 |
| 失敗メッセージ | HTML | 「No subscriptions were added」 |
| 抽出結果 | Text | メールアドレス抽出結果（Extract時） |

### 出力先

HTML画面（管理画面内）、データベース

## 処理フロー

### 処理シーケンス

```
1. アクセス権限チェック
   └─ secondAdmin.bNewsletter権限の確認
   └─ bCanImportSubscribers（カテゴリ存在）の確認
2. カテゴリ一覧の取得
   └─ customer.NewsletterCategoriesプロパティで取得
3. メールアドレス抽出処理（Extract時）
   └─ privatebotクラスでテキストからメールアドレスを抽出
4. インポート処理（Import時）
   └─ カテゴリ選択の必須チェック
   └─ インポート形式に応じたデータパース
   └─ 各カテゴリに対してループ処理
   └─ メールアドレス形式検証
   └─ 重複チェック（既存登録確認）
   └─ 新規レコード作成
5. 結果表示
   └─ 登録件数または失敗メッセージを表示
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B{bNewsletter権限あり?}
    B -->|No| C[アクセス拒否]
    B -->|Yes| D{bCanImportSubscribers?}
    D -->|No| E[一覧画面へリダイレクト]
    D -->|Yes| F[カテゴリ一覧取得]
    F --> G{btnaction?}
    G -->|Extract| H[メールアドレス抽出]
    H --> I[抽出結果表示]
    G -->|Import| J{カテゴリ選択あり?}
    J -->|No| K[必須エラー表示]
    J -->|Yes| L[データパース]
    L --> M[各カテゴリにループ]
    M --> N[各行にループ]
    N --> O{メール形式OK?}
    O -->|No| P[スキップ]
    O -->|Yes| Q{既存登録あり?}
    Q -->|Yes| P
    Q -->|No| R[新規レコード作成]
    R --> S[カウンタ加算]
    S --> P
    P --> T{次の行あり?}
    T -->|Yes| N
    T -->|No| U{次のカテゴリあり?}
    U -->|Yes| M
    U -->|No| V[結果表示]
    I --> W[終了]
    V --> W
    K --> W
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | 権限チェック | セカンドアドミンはbNewsletter権限が必要 | 全アクセス時 |
| BR-002 | カテゴリ必須 | カテゴリが1件以上必要（bCanImportSubscribers） | 画面表示時 |
| BR-003 | カテゴリ選択必須 | インポート時は最低1つのカテゴリを選択 | Import時 |
| BR-004 | メール形式検証 | 有効なメールアドレス形式のみ登録 | Import時 |
| BR-005 | 重複スキップ | 同一カテゴリ・同一メールアドレスは登録しない | Import時 |
| BR-006 | 単一カテゴリ自動選択 | カテゴリが1件のみの場合は自動選択 | フォーム表示時 |
| BR-007 | 有効/無効選択 | bimportinactiveで無効状態登録可能 | Import時 |

### 計算ロジック

- インポート形式0: カンマ区切りの「名前,メールアドレス」をパース
- インポート形式1: 改行区切りのメールアドレスのみをパース
- 登録成功件数: 新規登録されたレコード数をカウント

## データベース操作仕様

### 操作別データベース影響一覧

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| カテゴリ取得 | tblNewsletterCategory | SELECT | カテゴリ一覧取得 |
| 重複チェック | tblNewsletterCategorySubscriber | SELECT | 既存登録確認 |
| インポート | tblNewsletterCategorySubscriber | INSERT | 新規購読者作成 |

### テーブル別操作詳細

#### tblNewsletterCategorySubscriber

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | * | iCategoryID、sEmail条件 | 重複チェック |
| INSERT | sName | 入力値（最大50文字推定） | 形式0のみ |
| INSERT | sEmail | 入力メールアドレス（小文字変換） | 必須 |
| INSERT | sKey | ランダム生成（generatePassword x 3） | 配信解除用 |
| INSERT | iCategoryID | 選択カテゴリID | 必須 |
| INSERT | iCustomerID | cId | 顧客ID |
| INSERT | bActive | activeorinactive変数 | デフォルトtrue |
| INSERT | dAdded | date() | 登録日 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 権限エラー | bNewsletter権限なし | アクセス拒否 |
| - | カテゴリなし | bCanImportSubscribers=false | 一覧画面へリダイレクト |
| err_mandatory | 必須エラー | カテゴリ未選択 | エラーメッセージ表示 |
| - | 0件登録 | 有効データなし | 「No subscriptions were added」表示 |
| - | パースエラー | データ形式不正 | スキップして継続 |
| - | メール形式エラー | 不正なメールアドレス | スキップして継続 |

### リトライ仕様

エラー時は画面再表示、ユーザーによるデータ修正を促す

## トランザクション仕様

ADOのデフォルトトランザクション（自動コミット）を使用。各レコードは個別にINSERT。

## パフォーマンス要件

- インポート処理: 1000件あたり30秒以内
- メールアドレス抽出: 5秒以内

## セキュリティ考慮事項

- セカンドアドミン権限によるアクセス制御
- bCanImportSubscribersによる追加アクセス制御
- フォーム入力値のquotRep関数によるエスケープ
- メールアドレスの小文字正規化（大文字小文字の違いによる重複防止）
- 顧客IDによるデータ分離
- On Error Resume Nextによるエラーハンドリング（処理継続）

## 備考

- インポート形式:
  - 形式0: 「名前,メールアドレス」のカンマ区切り形式
  - 形式1: メールアドレスのみの改行区切り形式（デフォルト）
- 「Extract valid email addresses」機能により、任意のテキスト/HTMLからメールアドレスを自動抽出可能
- 複数カテゴリへの同時登録に対応
- 無効状態（bActive=false）でのインポートオプションあり
- 重複データは自動的にスキップ（既存登録との照合）
- エラーが発生してもスキップして処理を継続

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

まず、購読者とカテゴリのデータモデルを理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | newsletterCategory.asp | `asp/includes/newsletterCategory.asp` | cls_newsletterCategoryクラス、カテゴリ構造 |
| 1-2 | customer.asp | `asp/includes/customer.asp` | bCanImportSubscribersプロパティ（922-929行目） |

**読解のコツ**: tblNewsletterCategorySubscriberテーブルが購読者データを格納し、カテゴリとの関連はiCategoryIDで管理される。

#### Step 2: エントリーポイントを理解する

インポート画面の処理を確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | bs_newsletterImport.asp | `asp/bs_newsletterImport.asp` | インポートのメイン処理（1-84行目） |

**主要処理フロー**:
1. **4行目**: セキュリティチェック、bCanImportSubscribers確認
2. **5行目**: カテゴリ一覧取得
3. **13-65行目**: インポート処理（btnaction="Import"時）
4. **15-17行目**: カテゴリ選択必須チェック
5. **20-24行目**: 有効/無効状態の設定
6. **27-64行目**: カテゴリ・行の二重ループでインポート
7. **31-38行目**: インポート形式によるパース分岐
8. **40-58行目**: メール形式検証、重複チェック、レコード作成
9. **67-72行目**: メールアドレス抽出処理（Extract時）

#### Step 3: メールアドレス抽出機能を理解する

Extract機能で使用されるprivatebotクラスを確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | pb.asp | `asp/includes/pb.asp` | privatebotクラス、quickSearchメソッド |

**主要処理フロー**:
- **67-71行目（bs_newsletterImport.asp）**: privatebotインスタンス生成、quickSearch呼び出し
- pb.quickSearch: 任意のテキストからメールアドレスパターンを抽出

### プログラム呼び出し階層図

```
bs_newsletterImport.asp
    │
    ├─ bs_security.asp
    │      └─ logon.hasaccess (権限チェック)
    │
    ├─ customer.bCanImportSubscribers
    │      └─ カテゴリ存在確認
    │
    ├─ customer.NewsletterCategories
    │      └─ カテゴリ一覧取得
    │
    ├─ Import処理
    │      ├─ カテゴリループ
    │      │      └─ 行ループ
    │      │             ├─ データパース（形式による分岐）
    │      │             ├─ checkEmailSyntax() (メール形式検証)
    │      │             ├─ SELECT (重複チェック)
    │      │             └─ INSERT (新規登録)
    │      └─ 結果表示
    │
    └─ Extract処理
           └─ privatebot.quickSearch()
                  └─ メールアドレス抽出
```

### データフロー図

```
[入力]               [処理]                    [出力]

テキスト入力 ───▶ bs_newsletterImport.asp
(pairs)                  │
                         │
    ┌────────────────────┴────────────────────┐
    ▼                                          ▼
btnaction=Import                        btnaction=Extract
    │                                          │
    ▼                                          ▼
カテゴリループ                          privatebot.quickSearch()
    │                                          │
    ▼                                          ▼
行ループ                                抽出メールアドレス
    │                                    （テキストエリア表示）
    ├─ checkEmailSyntax()
    │
    ├─ 重複チェック ───▶ SELECT tblNewsletterCategorySubscriber
    │
    └─ 新規登録 ───▶ INSERT tblNewsletterCategorySubscriber
           │
           ▼
      登録件数表示
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| bs_newsletterImport.asp | `asp/bs_newsletterImport.asp` | ソース | 購読者インポート画面のメイン処理 |
| newsletterCategory.asp | `asp/includes/newsletterCategory.asp` | ソース | cls_newsletterCategoryクラス定義 |
| customer.asp | `asp/includes/customer.asp` | ソース | bCanImportSubscribers、NewsletterCategoriesプロパティ |
| pb.asp | `asp/includes/pb.asp` | ソース | privatebotクラス（メールアドレス抽出） |
| bs_security.asp | `asp/bs_security.asp` | ソース | 権限チェック処理 |
| header.asp | `asp/includes/header.asp` | テンプレート | HTMLヘッダー |
| footer.asp | `asp/includes/footer.asp` | テンプレート | HTMLフッター |
