Flask + SQLAlchemyで音楽共有SNSを作る - メッセージ送信機能編

## はじめに

前回の記事では、ユーザープロフィールページの実装について解説しました。今回は、ユーザー間のコミュニケーションを促進するメッセージ送信機能の実装について詳しく説明します。

## メッセージ送信機能の実装

以下に、メッセージ送信機能の実装コードを示します：

```python
from flask import render_template, flash, redirect, url_for
from flask_login import login_required, current_user
from app import app, db
from app.models import User, Message
from app.forms import MessageForm

@app.route('/send_message/<recipient>', methods=['GET', 'POST'])
@login_required
def send_message(recipient):
    user = User.query.filter_by(username=recipient).first_or_404()
    form = MessageForm()
    if form.validate_on_submit():
        msg = Message(sender=current_user, recipient=user,
                      body=form.message.data)
        db.session.add(msg)
        db.session.commit()
        flash('メッセージを送信しました。')
        return redirect(url_for('user', username=recipient))
    return render_template('send_message.html', title='メッセージ送信', form=form, recipient=recipient)
```

## 機能の詳細解説

1. **ルーティングとアクセス制御**
   ```python
   @app.route('/send_message/<recipient>', methods=['GET', 'POST'])
   @login_required
   ```
   - `<recipient>`は動的なURLパラメータで、メッセージの受信者のユーザー名を取得します。
   - `methods=['GET', 'POST']`で、GETリクエスト（フォーム表示）とPOSTリクエスト（メッセージ送信）の両方を処理します。
   - `@login_required`デコレータにより、ログインしているユーザーのみがアクセスできます。

2. **受信者の取得**
   ```python
   user = User.query.filter_by(username=recipient).first_or_404()
   ```
   - 指定された受信者名でデータベースを検索します。
   - `first_or_404()`メソッドにより、受信者が存在しない場合は自動的に404エラーを返します。

3. **フォームの作成と検証**
   ```python
   form = MessageForm()
   if form.validate_on_submit():
   ```
   - `MessageForm`インスタンスを作成します。
   - `validate_on_submit()`メソッドで、フォームが送信され、かつすべてのバリデーションに通過したかを確認します。

4. **メッセージの作成と保存**
   ```python
   msg = Message(sender=current_user, recipient=user,
                 body=form.message.data)
   db.session.add(msg)
   db.session.commit()
   ```
   - 新しい`Message`オブジェクトを作成し、送信者、受信者、メッセージ本文を設定します。
   - データベースセッションにメッセージを追加し、変更を確定します。

5. **フィードバックとリダイレクト**
   ```python
   flash('メッセージを送信しました。')
   return redirect(url_for('user', username=recipient))
   ```
   - フラッシュメッセージで送信成功を通知します。
   - 受信者のプロフィールページにリダイレクトします。

6. **フォーム表示**
   ```python
   return render_template('send_message.html', title='メッセージ送信', form=form, recipient=recipient)
   ```
   - GETリクエスト時、または検証エラー時に、メッセージ送信フォームを表示するテンプレートをレンダリングします。

## テンプレートの例

`send_message.html`テンプレートの例を以下に示します：

```html
{% extends "base.html" %}

{% block content %}
    <h1>{{ recipient }}さんにメッセージを送る</h1>
    <form action="" method="post">
        {{ form.hidden_tag() }}
        <p>
            {{ form.message.label }}<br>
            {{ form.message(cols=50, rows=4) }}<br>
            {% for error in form.message.errors %}
            <span style="color: red;">[{{ error }}]</span>
            {% endfor %}
        </p>
        <p>{{ form.submit() }}</p>
    </form>
{% endblock %}
```

## セキュリティとプライバシーの考慮点

1. **アクセス制御**: `@login_required`デコレータにより、認証されたユーザーのみがメッセージを送信できます。

2. **エラーハンドリング**: 存在しない受信者名でアクセスした場合、`first_or_404()`メソッドにより適切に404エラーを返します。

3. **CSRF対策**: Flask-WTFを使用することで、自動的にCSRF保護が適用されます。

4. **入力検証**: `MessageForm`のバリデーションにより、不適切なデータの送信を防ぎます。

## 今後の改善案

1. **メッセージ一覧機能**: ユーザーが受信したメッセージを一覧表示する機能を追加します。

2. **返信機能**: メッセージに対して直接返信できる機能を実装します。

3. **メッセージ削除機能**: ユーザーが不要なメッセージを削除できるようにします。

4. **ブロック機能**: 特定のユーザーからのメッセージを受け取らないオプションを追加します。

5. **通知機能**: 新しいメッセージが届いた際に通知を送る機能を実装します。

## まとめ

メッセージ送信機能の実装により、ユーザー間の直接的なコミュニケーションが可能になりました。この機能は以下の利点をもたらします：

1. ユーザー間の交流の促進
2. 音楽の趣味や情報に関する詳細な議論の場の提供
3. プライベートなコミュニケーションチャネルの確立

適切なセキュリティ対策を講じることで、安全で使いやすいメッセージング機能を提供できます。

## 参考リンク
- [Flask-WTF ドキュメント](https://flask-wtf.readthedocs.io/)
- [SQLAlchemy リレーションシップ](https://docs.sqlalchemy.org/en/14/orm/basic_relationships.html)
- [Flask フラッシュメッセージング](https://flask.palletsprojects.com/en/2.0.x/patterns/flashing/)