Claire_S
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
      • Invitee
    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Versions and GitHub Sync Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
Invitee
Publish Note

Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

Your note will be visible on your profile and discoverable by anyone.
Your note is now live.
This note is visible on your profile and discoverable online.
Everyone on the web can find and read all notes of this public team.
See published notes
Unpublish note
Please check the box to agree to the Community Guidelines.
View profile
Engagement control
Commenting
Permission
Disabled Forbidden Owners Signed-in users Everyone
Enable
Permission
  • Forbidden
  • Owners
  • Signed-in users
  • Everyone
Suggest edit
Permission
Disabled Forbidden Owners Signed-in users Everyone
Enable
Permission
  • Forbidden
  • Owners
  • Signed-in users
Emoji Reply
Enable
Import from Dropbox Google Drive Gist Clipboard
   owned this note    owned this note      
Published Linked with GitHub
Subscribed
  • Any changes
    Be notified of any changes
  • Mention me
    Be notified of mention me
  • Unsubscribe
Subscribe
## 0804 > 明天簡報問題: IATA NDC/ IATA One Record > 開始陸續詢問各單位有沒有填寫清冊上的問題。 資料庫: [flask+mysql](https://medium.com/seaniap/python-web-flask-flask-sqlalchemy%E6%93%8D%E4%BD%9Cmysql%E8%B3%87%E6%96%99%E5%BA%AB-2a799acdec4c) [py cache](https://ithelp.ithome.com.tw/articles/10363747) [sql 修改資料](https://ithelp.ithome.com.tw/articles/10220040) [sqlite&mysql的區別](https://medium.com/erens-tech-book/sqlite-%E8%88%87-mysql-%E7%9A%84%E5%B7%AE%E5%88%A5-a14926030ddd) [sqlite教程](https://www.runoob.com/sqlite/sqlite-commands.html) [ETCD入門](https://hackmd.io/@AmdAc990TDm3EkP4EmImTA/BygRA9q7P) 錯誤訊息: > [sqlalchemy.exc.IntegrityError: UNIQUE constraint failed](https://stackoverflow.com/questions/62688192/sqlalchemy-exc-integrityerror-unique-constraint-failed) -- 這個是id類的重複(id是不能重複的);避免這個問題,以Username舉例可以這樣確認 ```python # 新增前先查詢 @app.route('/') def index(): user = User.query.filter_by(username='alice').first() if not user: user = User(username='alice') db.session.add(user) db.session.commit() return "新增成功" else: return "使用者已存在" ``` > 問題:sqlite的檔名到底是什麼(還有他的註解方式,能不能用vscode寫) 感覺要想的很多 瓜張 ## 0805 好讚,修掉回到上一頁還會有資訊的問題了。 在main.py裡面加上no_cache ```python def no_cache(rendered_template): response = make_response(rendered_template) response.headers['Cache-Control'] = 'no-store, no-cache, must-revalidate, max-age=0' response.headers['Pragma'] = 'no-cache' response.headers['Expires'] = '-1' return response ``` *在開發軟體之前,要先了解並確認相關的需求才能進行下一步。 (看要不要找腿庫朋友確認一下) **- 軟體開發需求分析** - 文件資訊 |項目|說明| |----|----| |專案名稱|會員管理系統| |文件版本|v0.1| |撰寫日期|2025-08-05| |撰寫人|閃嘉珮| 1. 專案背景與目標 本統旨在提供一套簡易而完整的會員資訊管理平台,能夠支援**會員新增、查詢、修改與刪除**,並具備登入控管與基本資料驗證功能,以協助管理者維護會員清單、聯絡資訊與基本統計。 2. 使用者角色 |角色|權限描述| |----|----| |後台端使用者|可登入、檢視、編輯、刪除與新增會員資訊| 3. 功能需求 |編號|功能名稱|描述| |----|----|----| |FR-001|使用者登入|1.需要有能夠輸入帳號密碼的位置 <br>2.密碼輸入需要遮罩<br>3. 登入需做驗證,登入失敗需要跳出錯誤訊息| |FR-002|登出功能|點選登出會回到登入頁面,並清除登入資訊。| |FR-003|查詢會員資料|使用者可以查詢會員清單,查詢的機制:<br>1.會員卡號的搜尋必須要有完全一樣的卡號。<br>2.姓名搜尋可以模糊比對的方式找出符合條件的會員資料。<br>查詢成功後須於下方廠出表格並提供有連結可點選的會員卡號| |FR-004|編輯/刪除會員資料|1.使用者可編輯/刪除會員資料<br>2.任何資料異動皆須跳出確認視窗,按下確後才會進行後續動作<br>3.異動成功後會回到「查詢會員資訊」頁面| |FR-005|新增會員資料|1.使用者可新增會員資料<br>2.任何資料異動皆須跳出確認視窗,按下確後才會進行後續動作<br>3.新增成功後會回到「首頁」頁面| 4. 非功能需求 |編號|功能名稱|描述| |----|----|----| |NFR-001|資料驗證|欄位格式需正確| |NFR-002|安全性|使用session控管登入狀態| 5. 資料欄位與格式 |欄位名稱|類型|描述|限制| |----|----|----|----| |id|INTEGER|系統流水號|PRIMARY KEY, AUTOINCREMENT| |member_number|TEXT|會員編號|UNIQUE, NOT NULL| |family_name|TEXT|姓氏|NOT NULL| |given_name|TEXT|名字|NOT NULL| |sex|TEXT|性別|M或F| |date_of_birth|DATE|出生日期|NOT NULL| |email|TEXT|信箱|格式須合法| |phone_home|TEXT|住家電話|可空值| |phone_office|TEXT|公司電話|可空值| |phone_mobile|TEXT|行動電話|可空值| |country|TEXT|國家|可空值| |address|TEXT|地址|可空值| 6. 權限與安全需求 7. 後續擴充建議 [DDoS attack](https://www.cloudflare.com/zh-tw/learning/ddos/what-is-a-ddos-attack/) - DDoS attack 分散式阻斷服務攻擊是一種惡意嘗試,它利用大量的網際網路流量使目標伺服器或其周圍的基礎架構不堪重負,從而阻斷目標伺服器、服務或網路的正常流量。 - 如何識別DDoS攻擊 最明顯的症狀是,網站或服務突然變慢或不可用,但由於多種原因也有可能歲的效能問題;從流量分析工具可以幫助我們發現DDoS攻擊的一些明顯跡象。 - 來自單個IP位址或IP範圍的可疑流量 - 大量流量來自擁有單一行為特徵(例如裝置類型、地理位置或Web瀏覽器版本)的使用者 - 對單一頁面或端點的請求出現無法解釋的激增 - 奇怪的流量模式: 如在非正常時段激增,或不自然的模式(例如每10分鐘就激增) - OSI模型 神奇7層,整理一下每層在幹嘛。 [secure by design](https://blog.cloudflare.com/secure-by-design-principles/) [DDoS阻斷服務攻擊](https://zh.wikipedia.org/wiki/%E9%98%BB%E6%96%B7%E6%9C%8D%E5%8B%99%E6%94%BB%E6%93%8A) > 代辦: > 資訊人員ppt > 軟體開發需求分析 ## 0808 原本的IRM (Information Rights Management) - 是早期Office (2010、2013、2016)支援的權限控管技術。 - 可以限制文件的操作例如: - 禁止轉寄、列印、複製 - 設定存取過期時間 - 功能較單一,缺乏智慧分類與可視化監控 PIP (Purview Information Protection) 是IRM的雲端延伸與整合體 - Microsoft 將原本的 AIP(Azure Information Protection) 與 Microsoft Compliance、DLP、MIP整合進 Microsoft Purview 平台。 - 新一代資料標籤+敏感性分類+權限控管的整合方案。 #### Why 這次M365整合需要安裝PIP呢? 答: 1. IRM 的技術已過時,無法與雲端協作應用(如Teams, OneDrive)完美整合。 2. IRM不支援自動分類、自動標籤、審核日誌等功能。 3. PIP 支援機密等級標籤,可應用於郵件、文件、Teams訊息等。 4. PIP 支援自動分類、條件式存取、審計追蹤。 ### MITRE ATT&CK [MITRE ATT&CK](https://attack.mitre.org/) [D3FEND MATRIX](https://d3fend.mitre.org/) [OSINT framework](https://osintframework.com/) [CVSS Score Distribution for Top 50 Product By Total Number of Distinct Vulnerabilities](https://www.cvedetails.com/top-50-product-cvssscore-distribution.php) ## 0812 好久沒記,東西有點多 0813 - TCP/IP 介紹 0815 - 電腦系統作業環境介紹、Winmatrix、會員系統Demo [winmatrix](http://www.simopro.com/Standard/Standard.htm) 0812端點防護review 1. EADM除了資料交換的機制,還包含公司內部提權的操作,以及檢核當天裝了什麼軟體(無論是有沒有提權都會檢核) 2. Symantec 防毒是不包含防火牆跟IPS的! 3. 我們只有使用D-Security的浮水印功能,在這頁列出的**檔案加密、權限控管、外洩防護、裝置管控跟離線保護**實際上都是用**IRM來操作** ![image](https://hackmd.io/_uploads/r1byrK__ge.png) *補充: 後續改版的MIP僅提供雲端檔案保護,超刺激。 要思考的問題: 1. 是不是層層防護(把SEP跟D-Security加在一起)是不是就百毒不侵?會不會有沒擋住造成一線天的問題?要怎麼處理? 2. Winmatrix的功能、目前有用到的功能、你覺得哪些會需要用(下次簡報)。 ## 0821 0827更新 零件打包場: main.py ``` from flask import Flask, render_template, request, redirect, url_for, session, make_response from werkzeug.security import generate_password_hash, check_password_hash import sqlite3, os, re app = Flask(__name__) app.secret_key = os.environ.get('FLASK_SECRET_KEY','fallback_key') DB_PATH = os.path.join(os.path.dirname(__file__), 'member.db') def no_cache(content): response = make_response(content) response.headers['Cache-Control'] = 'no-store, no-cache, must-revalidate, max-age=0' response.headers['Pragma'] = 'no-cache' response.headers['Expires'] = '-1' return response def is_valid_input(data): return bool(re.match(r"^[a-zA-Z0-9_]{2,30}$", data)) def is_valid_password(password): count = 0 if re.search(r'[A-Z]', password): count += 1 if re.search(r'[a-z]', password): count += 1 if re.search(r'[0-9]', password): count += 1 if re.search(r'[!@#$%^&*(),.?\":{}|<>]', password): count += 1 return count >= 3 and len(password) >= 8 def authenticate_user(account, password): conn = sqlite3.connect(DB_PATH) c = conn.cursor() c.execute("SELECT password FROM users WHERE account = ?", (account,)) row = c.fetchone() conn.close() return row and check_password_hash(row[0], password) @app.route('/login.html') def login_page(): return no_cache(render_template('login.html')) @app.route('/login', methods=['POST']) def login(): account = request.form.get('account') password = request.form.get('password') if not account or not password or not is_valid_input(account) or not is_valid_password(password): return no_cache(render_template('login.html', error="格式錯誤")) if authenticate_user(account, password): session['user'] = account return redirect('/homepage.html') return no_cache(render_template('login.html', error="帳號或密碼錯誤")) @app.route('/homepage.html') def homepage(): if 'user' in session: return no_cache(render_template('homepage.html', user=session['user'])) return redirect('/login.html') @app.route('/logout', methods=['POST']) def logout(): session.clear() return redirect('/login.html') @app.route('/member_Add.html') def member_add_page(): if 'user' not in session: return redirect('/login.html') return no_cache(render_template('member_Add.html', user=session['user'])) @app.route('/add_member', methods=['POST']) def add_member(): if 'user' not in session: return redirect('/login.html') data = {k: request.form.get(k, '').strip() for k in [ 'family_name', 'given_name', 'sex', 'date_of_birth', 'email', 'phonenum_h', 'phonenum_o', 'phonenum_m', 'country', 'address', 'id_number' ]} # 基本必填檢查 if not data['family_name'] or not data['given_name'] or not data['sex'] or not data['id_number']: return no_cache(render_template('member_Add.html', user=session['user'], success="欄位不可空白")) conn = sqlite3.connect(DB_PATH) c = conn.cursor() # 以 id_number 防重複新增 c.execute("SELECT 1 FROM members WHERE id_number = ?", (data['id_number'],)) if c.fetchone(): conn.close() return no_cache(render_template('member_Add.html', user=session['user'], success="此身分/護照號碼已存在,請勿重複新增")) c.execute("SELECT MAX(id) FROM members") max_id = c.fetchone()[0] next_id = (max_id or 0) + 1 member_number = f"M{next_id:05d}" c.execute(''' INSERT INTO members (member_number, family_name, given_name, sex, dob, email, phone_h, phone_o, phone_m, country, address, id_number) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ''', (member_number, data['family_name'], data['given_name'], data['sex'], data['date_of_birth'], data['email'], data['phonenum_h'], data['phonenum_o'], data['phonenum_m'], data['country'], data['address'], data['id_number'])) conn.commit() conn.close() return f''' <script> alert("✅ 會員新增成功!會員編號為 {member_number}"); window.location.href = "/homepage.html"; </script> ''' @app.route('/member_Info.html') def member_info_page(): if 'user' not in session: return redirect('/login.html') return no_cache(render_template('member_Info.html', user=session['user'])) @app.route('/search_member', methods=['POST']) def search_member(): if 'user' not in session: return redirect('/login.html') number = request.form.get('member_num', '').strip() family = request.form.get('family_name', '').strip() given = request.form.get('given_name', '').strip() conn = sqlite3.connect(DB_PATH) conn.row_factory = sqlite3.Row c = conn.cursor() rows = [] if number: c.execute("SELECT member_number, family_name, given_name FROM members WHERE member_number = ?", (number,)) rows = c.fetchall() elif family and given: query = ''' SELECT member_number, family_name, given_name FROM members WHERE (family_name = ? AND given_name = ?) OR (family_name = ? AND substr(given_name, 1, 2) LIKE ?) OR (given_name = ? AND family_name = ?) OR (substr(given_name, 1, 2) LIKE ? AND family_name = ?) ''' args = (family, given, family, given[:2], family, given, family[:2], given) c.execute(query, args) rows = c.fetchall() elif family: c.execute("SELECT member_number, family_name, given_name FROM members WHERE family_name LIKE ?", (f"%{family}%",)) rows = c.fetchall() elif given: c.execute("SELECT member_number, family_name, given_name FROM members WHERE given_name LIKE ?", (f"%{given}%",)) rows = c.fetchall() conn.close() if rows: return no_cache(render_template('member_Info.html', user=session['user'], results=rows)) else: return no_cache(render_template('member_Info.html', user=session['user'], error="找不到符合的會員")) # 修正:使用路由參數,不再讀 request.args @app.route('/member_Update.html/<member_number>') def member_update(member_number): if 'user' not in session: return redirect('/login.html') conn = sqlite3.connect(DB_PATH) conn.row_factory = sqlite3.Row c = conn.cursor() c.execute("SELECT * FROM members WHERE member_number = ?", (member_number,)) result = c.fetchone() conn.close() return no_cache(render_template('member_Update.html', user=session['user'], member=result)) @app.route('/update_member', methods=['POST']) def update_member(): if 'user' not in session: return redirect('/login.html') member_number = request.form['member_number'] # 先抓舊資料,檢查 id_number 是否更動/衝突 conn = sqlite3.connect(DB_PATH) conn.row_factory = sqlite3.Row c = conn.cursor() c.execute("SELECT id, id_number FROM members WHERE member_number = ?", (member_number,)) current = c.fetchone() if not current: conn.close() return redirect(url_for('member_info_page')) new_values = { 'family_name': request.form.get('family_name','').strip(), 'given_name': request.form.get('given_name','').strip(), 'sex': request.form.get('sex','').strip(), 'dob': request.form.get('dob','').strip(), 'email': request.form.get('email','').strip(), 'phone_h': request.form.get('phone_h','').strip(), 'phone_o': request.form.get('phone_o','').strip(), 'phone_m': request.form.get('phone_m','').strip(), 'country': request.form.get('country','').strip(), 'address': request.form.get('address','').strip(), 'id_number': request.form.get('id_number','').strip() or None } # 若新 id_number 與其他會員衝突 → 拒絕 if new_values['id_number'] is not None: c.execute("SELECT member_number FROM members WHERE id_number = ? AND member_number != ?", (new_values['id_number'], member_number)) conflict = c.fetchone() if conflict: conn.close() return f''' <script> alert("此身分/護照號碼已被會員 {conflict['member_number']} 使用,請更換後再試。"); window.history.back(); </script> ''' c.execute(''' UPDATE members SET family_name=?, given_name=?, sex=?, dob=?, email=?, phone_h=?, phone_o=?, phone_m=?, country=?, address=?, id_number=? WHERE member_number=? ''', (new_values['family_name'], new_values['given_name'], new_values['sex'], new_values['dob'], new_values['email'], new_values['phone_h'], new_values['phone_o'], new_values['phone_m'], new_values['country'], new_values['address'], new_values['id_number'], member_number)) conn.commit() conn.close() return redirect(url_for('member_info_page')) # 刪除:統一路徑為 /delete_member/<member_number> 搭配 POST @app.route('/delete_member/<member_number>', methods=['POST']) def delete_member(member_number): if 'user' not in session: return redirect('/login.html') conn = sqlite3.connect(DB_PATH) c = conn.cursor() c.execute("DELETE FROM members WHERE member_number = ?", (member_number,)) conn.commit() conn.close() return redirect(url_for('member_info_page')) @app.route('/session_check') def session_check(): if 'user' not in session: return '', 401 return '', 200 if __name__ == '__main__': app.run(debug=True) ``` db_init.py ``` import sqlite3 from werkzeug.security import generate_password_hash conn = sqlite3.connect('member.db') c = conn.cursor() c.execute(''' CREATE TABLE IF NOT EXISTS users ( id INTEGER PRIMARY KEY AUTOINCREMENT, account TEXT UNIQUE NOT NULL, password TEXT NOT NULL ) ''') c.execute(''' CREATE TABLE IF NOT EXISTS members ( id INTEGER PRIMARY KEY AUTOINCREMENT, member_number TEXT UNIQUE NOT NULL, family_name TEXT NOT NULL, given_name TEXT NOT NULL, sex TEXT NOT NULL, dob TEXT, email TEXT, phone_h TEXT, phone_o TEXT, phone_m TEXT, country TEXT, address TEXT, id_number TEXT ) ''') # 只對非空值做唯一限制 c.execute(''' CREATE UNIQUE INDEX IF NOT EXISTS ux_members_id_number_notnull ON members(id_number) WHERE id_number IS NOT NULL ''') hashed_pw = generate_password_hash('!Claire0320') c.execute('INSERT OR IGNORE INTO users (account, password) VALUES (?, ?)', ('Claire', hashed_pw)) conn.commit() conn.close() print("✅ 資料庫建立完成(含 id_number 唯一索引);預設帳號 Claire / !Claire0320") ``` insert_test_data.py ``` import sqlite3 conn = sqlite3.connect("member.db") c = conn.cursor() test_data = [ ("M00001", "Shan", "Albert", "M", "1985-01-01", "a@example.com", "02-12345678", "03-87654321", "0912-345678", "Taiwan", "Taipei", "A123456789"), ("M00002", "Shan", "Claire", "F", "1986-01-01", "b@example.com", "02-11111111", "03-22222222", "0912-000000", "Taiwan", "Kaohsiung", "B223456789"), ("M00003", "Chen", "Janna", "F", "1987-01-01", "c@example.com", "02-33333333", "03-44444444", "0912-111111", "Taiwan", "Tainan", None), ("M00004", "Shan", "Kelly", "F", "1988-01-01", "d@example.com", "02-55555555", "03-66666666", "0912-222222", "Taiwan", "Taichung", "K123456789"), ("M00005", "Chen", "Kelly", "F", "1988-01-01", "e@example.com", "02-77777777", "03-88888888", "0912-333333", "Taiwan", "Taichung", None), ] for row in test_data: c.execute(''' INSERT INTO members ( member_number, family_name, given_name, sex, dob, email, phone_h, phone_o, phone_m, country, address, id_number ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ''', row) conn.commit() conn.close() print("✅ 測試資料新增完成(含 id_number)") ``` view_db.py ``` import sqlite3 DB_PATH = 'member.db' conn = sqlite3.connect(DB_PATH) conn.row_factory = sqlite3.Row c = conn.cursor() print("📋 users 表:") for row in c.execute("SELECT * FROM users"): print(dict(row)) print("\n📋 members 表:") for row in c.execute("SELECT * FROM members"): print(dict(row)) conn.close() ``` homepage.html ``` <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Home</title> </head> <body> <p>User ID: {{ user }}</p> <ul> <li><a href="/member_Info.html">Member Query</a></li> <li><a href="/member_Add.html">Add New Member</a></li> </ul> <form action="/logout" method="post"><button type="submit">Logout</button></form> <script>window.addEventListener("pageshow", function () { fetch('/session_check', { cache: 'no-store' }).then(res => { if (!res.ok) window.location.href = '/login.html'; }); });</script> </body> </html> ``` login.html ``` <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Login</title> </head> <body> <form action="/login" method="post" autocomplete="off"> <label>Account:</label><input type="text" name="account" autocomplete="off"><br><br> <label>Password:</label><input type="password" name="password" autocomplete="off"><br><br> <button type="submit">Login</button> </form> <script>window.onload = () => document.querySelectorAll("input").forEach(i => i.value = '');</script> {% if error %} <script>alert("{{ error }}");</script> {% endif %} </body> </html> ``` member_Add.html ``` <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Member Add</title> </head> <body> <p>User ID: {{ user }}</p> <form action="/add_member" method="post" onsubmit="return confirm('請確認以下資料是否要送出');"> <label>Family Name:</label> <input type="text" name="family_name" pattern="^[a-zA-Z]{2,30}$" required><br><br> <label>Given Name:</label> <input type="text" name="given_name" pattern="^[a-zA-Z]{2,30}$" required><br><br> <label>Sex:</label> <input type="text" name="sex" pattern="^(M|F)$" required><br><br> <label>Date of Birth:</label> <input type="text" name="date_of_birth" pattern="^\d{4}-(0?[1-9]|1[0-2])-(0?[1-9]|[12]\d|3[01])$"><br><br> <label>Email:</label> <input type="text" name="email" pattern="^[\w.-]+@[\w.-]+\.[A-Za-z]{2,}$"><br><br> <label>Phone H:</label> <input type="text" name="phonenum_h" pattern="^[0-9-]{7,20}$"><br><br> <label>Phone O:</label> <input type="text" name="phonenum_o" pattern="^[0-9-]{7,20}$"><br><br> <label>Phone M:</label> <input type="text" name="phonenum_m" pattern="^[0-9-]{7,20}$"><br><br> <label>Country:</label> <input type="text" name="country" pattern="^[a-zA-Z0-9\u4e00-\u9fa5\s]{2,50}$"><br><br> <label>Address:</label> <input type="text" name="address" pattern="^[a-zA-Z0-9\u4e00-\u9fa5\s,#-]{2,100}$"><br><br> <label>身分證/護照號碼 (ID/Passport):</label> <input type="text" name="id_number" pattern="^[A-Z0-9]{6,12}$" required placeholder="僅限大寫英數 6–12 碼"><br><br> <button type="submit">Save</button> </form> {% if success %} <script>alert("{{ success }}");</script> {% endif %} <br><button onclick="history.back()">Back</button> </body> </html> ``` member_Info.html ``` <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Member Info</title> </head> <body> <p>User ID: {{ user }}</p> <form action="/search_member" method="post"> <label>Member Number:</label><input type="text" name="member_num"><br><br> <label>Family Name:</label><input type="text" name="family_name"><br><br> <label>Given Name:</label><input type="text" name="given_name"><br><br> <button type="submit">Search</button> </form> <hr> {% if results %} <table border="1" cellpadding="5"> <tr><th>Member Number</th><th>Family Name</th><th>Given Name</th></tr> {% for row in results %} <tr> <td><a href="{{ url_for('member_update', member_number=row.member_number) }}">{{ row.member_number }}</a></td> <td>{{ row.family_name }}</td> <td>{{ row.given_name }}</td> </tr> {% endfor %} </table> {% elif error %} <p style="color: red;">{{ error }}</p> {% endif %} <br><button onclick="window.location.href='/homepage.html'">Back</button> </body> </html> ``` member_Update.html ``` <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Update Member</title> </head> <body> <p>User ID: {{ user }}</p> <h3>Update Member Info</h3> {% if member %} <form action="/update_member" method="post" onsubmit="return confirm('確認更新此會員資料?');"> <p>Member Number: <strong>{{ member.member_number }}</strong></p> <input type="hidden" name="member_number" value="{{ member.member_number }}"> <label>Family Name:</label> <input type="text" name="family_name" value="{{ member.family_name }}" pattern="^[a-zA-Z]{2,30}$" required><br><br> <label>Given Name:</label> <input type="text" name="given_name" value="{{ member.given_name }}" pattern="^[a-zA-Z]{2,30}$" required><br><br> <label>Sex (M/F):</label> <input type="text" name="sex" value="{{ member.sex }}" pattern="^(M|F)$" required><br><br> <label>Date of Birth:</label> <input type="text" name="dob" value="{{ member.dob }}" pattern="^\d{4}-(0?[1-9]|1[0-2])-(0?[1-9]|[12][0-9]|3[01])$"> <br><br> <label>Email:</label> <input type="text" name="email" value="{{ member.email }}" pattern="^[\\w.-]+@[\\w.-]+\\.[A-Za-z]{2,}$"><br><br> <label>Phone Number (H):</label> <input type="text" name="phone_h" value="{{ member.phone_h }}" pattern="^[0-9-]{7,20}$"><br><br> <label>Phone Number (O):</label> <input type="text" name="phone_o" value="{{ member.phone_o }}" pattern="^[0-9-]{7,20}$"><br><br> <label>Phone Number (M):</label> <input type="text" name="phone_m" value="{{ member.phone_m }}" pattern="^[0-9-]{7,20}$"><br><br> <label>Country:</label> <input type="text" name="country" value="{{ member.country }}" pattern="^[a-zA-Z0-9\\u4e00-\\u9fa5\\s]{2,50}$"><br><br> <label>Address:</label> <input type="text" name="address" value="{{ member.address }}" pattern="^[a-zA-Z0-9\\u4e00-\\u9fa5\\s,#-]{2,100}$"><br><br> <label>身分證/護照號碼 (ID/Passport):</label> <input type="text" name="id_number" value="{{ member.id_number }}" pattern="^[A-Z0-9]{6,12}$" required><br><br> <button type="submit">Update</button> </form> <form action="/delete_member/{{ member.member_number }}" method="post" onsubmit="return confirm('確定要刪除會員?');"> <button type="submit" style="margin-top:10px;">Delete Member</button> </form> {% else %} <p style="color:red;">查無此會員</p> {% endif %} <br> <button onclick="window.location.href='/member_Info.html'">Back</button> </body> </html> ``` ## 0826 ![image](https://hackmd.io/_uploads/Hy6UDAqFgx.png) [OU參考資料](https://learn.microsoft.com/zh-tw/windows-server/identity/ad-ds/plan/delegating-administration-of-account-ous-and-resource-ous)

Import from clipboard

Paste your markdown or webpage here...

Advanced permission required

Your current role can only read. Ask the system administrator to acquire write and comment permission.

This team is disabled

Sorry, this team is disabled. You can't edit this note.

This note is locked

Sorry, only owner can edit this note.

Reach the limit

Sorry, you've reached the max length this note can be.
Please reduce the content or divide it to more notes, thank you!

Import from Gist

Import from Snippet

or

Export to Snippet

Are you sure?

Do you really want to delete this note?
All users will lose their connection.

Create a note from template

Create a note from template

Oops...
This template has been removed or transferred.
Upgrade
All
  • All
  • Team
No template.

Create a template

Upgrade

Delete template

Do you really want to delete this template?
Turn this template into a regular note and keep its content, versions, and comments.

This page need refresh

You have an incompatible client version.
Refresh to update.
New version available!
See releases notes here
Refresh to enjoy new features.
Your user state has changed.
Refresh to load new user state.

Sign in

Forgot password

or

By clicking below, you agree to our terms of service.

Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
Wallet ( )
Connect another wallet

New to HackMD? Sign up

Help

  • English
  • 中文
  • Français
  • Deutsch
  • 日本語
  • Español
  • Català
  • Ελληνικά
  • Português
  • italiano
  • Türkçe
  • Русский
  • Nederlands
  • hrvatski jezik
  • język polski
  • Українська
  • हिन्दी
  • svenska
  • Esperanto
  • dansk

Documents

Help & Tutorial

How to use Book mode

Slide Example

API Docs

Edit in VSCode

Install browser extension

Contacts

Feedback

Discord

Send us email

Resources

Releases

Pricing

Blog

Policy

Terms

Privacy

Cheatsheet

Syntax Example Reference
# Header Header 基本排版
- Unordered List
  • Unordered List
1. Ordered List
  1. Ordered List
- [ ] Todo List
  • Todo List
> Blockquote
Blockquote
**Bold font** Bold font
*Italics font* Italics font
~~Strikethrough~~ Strikethrough
19^th^ 19th
H~2~O H2O
++Inserted text++ Inserted text
==Marked text== Marked text
[link text](https:// "title") Link
![image alt](https:// "title") Image
`Code` Code 在筆記中貼入程式碼
```javascript
var i = 0;
```
var i = 0;
:smile: :smile: Emoji list
{%youtube youtube_id %} Externals
$L^aT_eX$ LaTeX
:::info
This is a alert area.
:::

This is a alert area.

Versions and GitHub Sync
Get Full History Access

  • Edit version name
  • Delete

revision author avatar     named on  

More Less

Note content is identical to the latest version.
Compare
    Choose a version
    No search result
    Version not found
Sign in to link this note to GitHub
Learn more
This note is not linked with GitHub
 

Feedback

Submission failed, please try again

Thanks for your support.

On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

Please give us some advice and help us improve HackMD.

 

Thanks for your feedback

Remove version name

Do you want to remove this version name and description?

Transfer ownership

Transfer to
    Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

      Link with GitHub

      Please authorize HackMD on GitHub
      • Please sign in to GitHub and install the HackMD app on your GitHub repo.
      • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
      Learn more  Sign in to GitHub

      Push the note to GitHub Push to GitHub Pull a file from GitHub

        Authorize again
       

      Choose which file to push to

      Select repo
      Refresh Authorize more repos
      Select branch
      Select file
      Select branch
      Choose version(s) to push
      • Save a new version and push
      • Choose from existing versions
      Include title and tags
      Available push count

      Pull from GitHub

       
      File from GitHub
      File from HackMD

      GitHub Link Settings

      File linked

      Linked by
      File path
      Last synced branch
      Available push count

      Danger Zone

      Unlink
      You will no longer receive notification when GitHub file changes after unlink.

      Syncing

      Push failed

      Push successfully