cd2025 協同產品設計實習

  • Home
    • SMap
    • reveal
    • blog
  • About
    • Summary
      • Tasks
      • Closing
      • Shooter
    • Product
    • Control
    • CPS
    • AI
    • Project
  • Topics
    • Wink
      • Fossil
    • Topic1
      • w1
      • Portable
      • repo
      • SSH
      • list
      • IPv6
    • Topic2
      • Compile
      • Onshape
    • Topic3
      • Fourbar2
      • boomer
    • Topic4
      • ROS2
  • HW
    • HW1
    • HW2
    • HW3
  • Exam
    • Exam1
    • Exam2
    • Exam3
  • Final
    • Webots
    • Rotate
  • Tutorial
    • Fourbar
      • w10
    • Stage1
      • Tutorial1
      • Tutorial2
    • Stage2
      • Tutorial3
      • Distancesensor
      • Tutorial4
      • Tutorial5
    • Stage3
      • Tutorial6
      • Tutorial7
      • Stream
      • Webots Server
    • Solvespace
      • Learn_Solvs
    • Mecanum
    • Pyslvs-UI
    • PICSimLab
    • Fossil SCM
    • Leo Editor
    • uv
    • Old
  • Brython
AI << Previous Next >> Topics

Project

修課學員經由 @nfu.edu.tw 網域, 可利用"學號@nfu.edu.tw"經由 https://login.microsoftonline.com/ 登入 MS 365.

登入後, 使用者可以利用"應用程式註冊"建立應用程式.

所註冊的延伸應用程式則可以利用 Microsoft Online 主機所提供的 OAuth2 API 程式庫, 取得登入者的 profile.

經由上列步驟取得登入者的 profile 後, 延伸應用程式可設法讀取課程學員的作業倉儲與網站連結.

from flask import Flask, redirect, request, session, url_for
import requests
import json
 
app = Flask(__name__)
app.secret_key = 'your_secret_key'  # 用於 Flask session 的秘密金鑰
 
# 替換成你的 Azure AD 應用程式資訊
'''
取得 CLIENT_ID(應用程式 (用戶端) 識別碼)

    進入你的應用程式註冊細節頁面。
    在「概觀」分頁中,找到「應用程式 (用戶端) 識別碼」(Application (client) ID)。
    複製這個 GUID 字串,填入 CLIENT_ID = '這個字串'

建立 CLIENT_SECRET(用戶端密碼)

    在應用程式註冊的左側欄選單選擇「憑證與秘密」(Certificates & secrets)。
    點選「新增用戶端密碼」(New client secret)。
    填寫描述與存續期限,按下「新增」。
    建立後會出現一個「值」(Value),這才是 CLIENT_SECRET,只會顯示一次,請立即複製起來,填入 CLIENT_SECRET = '這個值'

取得 TENANT_ID(目錄 (租用戶) 識別碼)

    同樣在「概觀」分頁中,找到「目錄 (租用戶) 識別碼」(Directory (tenant) ID)。
    複製這個 GUID 字串,填入 TENANT_ID = '這個字串'
'''
CLIENT_ID = 'your_CLIENT_ID'
CLIENT_SECRET = 'your_CLIENT_SECRET'
TENANT_ID = 'your_TENANT_ID'
AUTHORITY = f'https://login.microsoftonline.com/{TENANT_ID}'
REDIRECT_URI = 'https://your_server_domain/callback'
SCOPE = 'User.Read'
 
# 用於登錄和取得授權碼
@app.route('/')
def index():
    auth_url = (f'{AUTHORITY}/oauth2/v2.0/authorize'
                f'?client_id={CLIENT_ID}'
                f'&response_type=code'
                f'&redirect_uri={REDIRECT_URI}'
                f'&response_mode=query'
                f'&scope={SCOPE}')
    return redirect(auth_url)
 
# 處理回調和交換授權碼
@app.route('/callback')
def callback():
    code = request.args.get('code')
    token_url = f'{AUTHORITY}/oauth2/v2.0/token'
    token_data = {
        'grant_type': 'authorization_code',
        'code': code,
        'redirect_uri': REDIRECT_URI,
        'client_id': CLIENT_ID,
        'client_secret': CLIENT_SECRET,
        'scope': SCOPE
    }
    token_r = requests.post(token_url, data=token_data)
    token_r.raise_for_status()
    tokens = token_r.json()
    session['access_token'] = tokens['access_token']
    return redirect(url_for('profile'))
 
# 使用訪問令牌呼叫 Microsoft Graph API 來獲取用戶資料
@app.route('/profile')
def profile():
    access_token = session.get('access_token')
    if not access_token:
        return redirect(url_for('index'))
 
    headers = {
        'Authorization': f'Bearer {access_token}',
        'Content-Type': 'application/json'
    }
    graph_url = 'https://graph.microsoft.com/v1.0/me'
    graph_r = requests.get(graph_url, headers=headers)
    graph_r.raise_for_status()
    user_info = graph_r.json()
    user_email = str(user_info["mail"])
    user_id = user_email.split("@")[0]
    session["user_id"] = user_id
    # 登出 MS Online 並重定向回首頁
    # 返回 HTML 及 JavaScript 以進行自動登出
    return (f'Hello, {user_id} <br>'
            f'<script type="text/javascript">'
            f'  window.location = "https://login.microsoftonline.com/common/oauth2/v2.0/logout";'
            f'</script>')
 
@app.route('/userid')
def userid():
    return session["user_id"]
     
 
# 登出功能
@app.route('/logout')
def logout():
    # 清除 session 中的訪問令牌
    session.pop('access_token', None)
    # 重定向到 MS Online 登出 URL
    return redirect('https://login.microsoftonline.com/common/oauth2/v2.0/logout')
 
if __name__ == '__main__':
    context = (r'C:\Certbot\live\your_server_domain\cert.pem', r'C:\Certbot\live\your_server_domain\privkey.pem')
    app.run(debug=True, host='your_server_domain', port=443, ssl_context=context)

啟動後, 以 https://your_server_domain 連線後, 系統導到 Office 365 登入.

以下則為寄信範例:

import requests
import json
 
# 替換為你的應用程式資訊
CLIENT_ID = 'your_client_id'
CLIENT_SECRET = 'your_client_secret'
TENANT_ID = 'your_tenant_id'
AUTHORITY = f'https://login.microsoftonline.com/{TENANT_ID}'
TOKEN_URL = f'{AUTHORITY}/oauth2/v2.0/token'
SCOPE = 'https://graph.microsoft.com/.default'
 
# 獲取 OAuth2 訪問令牌
def get_access_token():
    token_data = {
        'grant_type': 'client_credentials',
        'client_id': CLIENT_ID,
        'client_secret': CLIENT_SECRET,
        'scope': SCOPE
    }
    token_r = requests.post(TOKEN_URL, data=token_data)
    token_r.raise_for_status()
    tokens = token_r.json()
    return tokens['access_token']
 
# 發送電子郵件
def send_email(access_token, to_address, subject, body):
    headers = {
        'Authorization': f'Bearer {access_token}',
        'Content-Type': 'application/json'
    }
    email_data = {
        "message": {
            "subject": subject,
            "body": {
                "contentType": "Text",
                "content": body
            },
            "toRecipients": [
                {
                    "emailAddress": {
                        "address": to_address
                    }
                }
            ]
        },
        "saveToSentItems": "true"
    }
    email_url = 'https://graph.microsoft.com/v1.0/me/sendMail'
    response = requests.post(email_url, headers=headers, json=email_data)
    response.raise_for_status()
    print("Email sent successfully!")
 
if __name__ == "__main__":
    token = get_access_token()
    send_email(token, 'recipient@example.com', 'Test Subject', 'This is the email body.')

以下利用 ChatGPT 進行對話:

問:

使用 python + flask 開發一個簡單的資料庫程式, 並使用 SQLite, 目前表單有使用者學號以及其 github 帳號, 還有一個備註欄位, 只需要 add, query, update 與 delete 功能, 該如何進行?

答:

安裝 Flask 和 SQLite

首先,確保你已經安裝了 Flask 和 SQLite。如果你還沒有安裝,請使用以下命令:

pip install Flask

SQLite 通常已經隨 Python 安裝,不需要額外安裝。如果你需要 SQLite 的 Python 模組,可以使用以下命令:

pip install sqlite3

建立 Flask 應用程式

應用程式結構:

flask_app/
│
├── app.py
├── schema.sql
└── templates/
    ├── index.html
    ├── add.html
    ├── update.html
    └── query.html

schema.sql — 定義 SQLite 資料表

在 schema.sql 文件中,定義 SQLite 資料表結構:

CREATE TABLE IF NOT EXISTS users (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    student_id TEXT NOT NULL UNIQUE,
    github_account TEXT NOT NULL,
    notes TEXT
);

app.py — Flask 應用程式

在 app.py 中,設置 Flask 應用程式並建立 CRUD 功能:


from flask import Flask, request, redirect, url_for, render_template
import sqlite3
 
app = Flask(__name__)
 
DATABASE = 'database.db'
 
def get_db():
    conn = sqlite3.connect(DATABASE)
    conn.row_factory = sqlite3.Row
    return conn
 
def init_db():
    with app.app_context():
        db = get_db()
        with open('schema.sql', 'r') as f:
            db.executescript(f.read())
        db.commit()
 
@app.route('/')
def index():
    return render_template('index.html')
 
@app.route('/add', methods=['GET', 'POST'])
def add_user():
    if request.method == 'POST':
        student_id = request.form['student_id']
        github_account = request.form['github_account']
        notes = request.form.get('notes', '')
 
        db = get_db()
        db.execute('INSERT INTO users (student_id, github_account, notes) VALUES (?, ?, ?)',
                   (student_id, github_account, notes))
        db.commit()
        return redirect(url_for('index'))
 
    return render_template('add.html')
 
@app.route('/update/<int:user_id>', methods=['GET', 'POST'])
def update_user(user_id):
    db = get_db()
    if request.method == 'POST':
        student_id = request.form['student_id']
        github_account = request.form['github_account']
        notes = request.form.get('notes', '')
 
        db.execute('UPDATE users SET student_id = ?, github_account = ?, notes = ? WHERE id = ?',
                   (student_id, github_account, notes, user_id))
        db.commit()
        return redirect(url_for('index'))
 
    user = db.execute('SELECT * FROM users WHERE id = ?', (user_id,)).fetchone()
    return render_template('update.html', user=user)
 
@app.route('/delete/<int:user_id>')
def delete_user(user_id):
    db = get_db()
    db.execute('DELETE FROM users WHERE id = ?', (user_id,))
    db.commit()
    return redirect(url_for('index'))
 
@app.route('/query')
def query_users():
    db = get_db()
    users = db.execute('SELECT * FROM users').fetchall()
    return render_template('query.html', users=users)
 
if __name__ == '__main__':
    init_db()
    app.run(debug=True)

templates/index.html:

<!DOCTYPE html>
<html>
<head>
    <title>Index</title>
</head>
<body>
    <h1>Welcome to User Management</h1>
    <a href="{{ url_for('add_user') }}">Add User</a> |
    <a href="{{ url_for('query_users') }}">Query Users</a>
</body>
</html>

templates/add.html:

<!DOCTYPE html>
<html>
<head>
    <title>Add User</title>
</head>
<body>
    <h1>Add User</h1>
    <form action="{{ url_for('add_user') }}" method="post">
        <label for="student_id">Student ID:</label>
        <input type="text" id="student_id" name="student_id" required><br>
        <label for="github_account">GitHub Account:</label>
        <input type="text" id="github_account" name="github_account" required><br>
        <label for="notes">Notes:</label>
        <textarea id="notes" name="notes"></textarea><br>
        <input type="submit" value="Add">
    </form>
    <a href="{{ url_for('index') }}">Back</a>
</body>
</html>

templates/update.html:

<!DOCTYPE html>
<html>
<head>
    <title>Update User</title>
</head>
<body>
    <h1>Update User</h1>
    <form action="{{ url_for('update_user', user_id=user['id']) }}" method="post">
        <label for="student_id">Student ID:</label>
        <input type="text" id="student_id" name="student_id" value="{{ user['student_id'] }}" required><br>
        <label for="github_account">GitHub Account:</label>
        <input type="text" id="github_account" name="github_account" value="{{ user['github_account'] }}" required><br>
        <label for="notes">Notes:</label>
        <textarea id="notes" name="notes">{{ user['notes'] }}</textarea><br>
        <input type="submit" value="Update">
    </form>
    <a href="{{ url_for('index') }}">Back</a>
</body>
</html>

templates/query.html:

<!DOCTYPE html>
<html>
<head>
    <title>Query Users</title>
</head>
<body>
    <h1>Users</h1>
    <table>
        <tr>
            <th>ID</th>
            <th>Student ID</th>
            <th>GitHub Account</th>
            <th>Notes</th>
            <th>Actions</th>
        </tr>
        {% for user in users %}
        <tr>
            <td>{{ user['id'] }}</td>
            <td>{{ user['student_id'] }}</td>
            <td>{{ user['github_account'] }}</td>
            <td>{{ user['notes'] }}</td>
            <td>
                <a href="{{ url_for('update_user', user_id=user['id']) }}">Update</a> |
                <a href="{{ url_for('delete_user', user_id=user['id']) }}">Delete</a>
            </td>
        </tr>
        {% endfor %}
    </table>
    <a href="{{ url_for('index') }}">Back</a>
</body>
</html>

啟動應用程式

確保你的 Flask 應用程式和模板文件已經正確配置,然後啟動應用程式:

python app.py

接下來, 可以在瀏覽器中訪問 http://127.0.0.1:5000/ 來查看和管理你的資料。


AI << Previous Next >> Topics

Copyright © All rights reserved | This template is made with by Colorlib