Author: kanakorn.h

  • วิธีแจ้งเตือนจาก Google Forms เข้า LINE

    ต้องยอมรับว่า ปัจจุบันพฤติกรรมผู้ใช้ “ทั่วไป” จะเปิด LINE อ่านบ่อย และเร็วกว่าการเปิดอ่าน Email

    ต่อไปนี้ เป็นวิธีการ ตั้งค่าที่ Google Forms ว่า เมื่อมีคน Submit แบบฟอร์มมา ให้มา Alert ที่ LINE ของเรา หรือ ส่งเข้า LINE Group ก็ได้ โดยอาศัยความสามารถของ Google App Scripts ที่เรียก REST API ของ LINE

    สร้าง หรือ แก้ไข Google Forms ที่ต้องการ

    จากนั้น ไปที่ “More” หรือ ปุ่มสามจุดแนวตั้งด้านขวามือบน แล้ว คลิกที่ Script Editor

    จากนั้น ใส่ Google App Script

    ตามนี้ ในที่นี้ ตั้งชื่อ Function คือ sendLineNotification

    **** อย่าลืมเปลี่ยน YOUR-TOKEN-GO-HERE ที่จะได้จากขั้นตอนต่อไป ****

    function sendLineNotification(e)
    {
      // เลือกใช้ Form ที่กำลังใช้งานนี้
      var form = FormApp.getActiveForm() 
      
      // รับค่าจาก Form Response
      var itemResponses = e.response.getItemResponses();  
      
      // ข้อความที่แสดงในบรรทัดแรก
      var result="New Response" 
      
      // Loop แต่ละข้อคำถาม และ คำตอบ
      for (var i = 0; i < itemResponses.length; i++) {
        var itemResponse = itemResponses[i];
        
        // ต่อข้อความจากทุกคำถาม เป็นข้อความยาวข้อความเดียว
        // getTitle คือ Question Title แต่ละข้อ
        // getResponse คือ ถามตอบที่ส่งมา
        result += '\n'+itemResponse.getItem().getTitle()+': '+itemResponse.getResponse()
      }
      
      // สร้างรูปแบบที่จะส่งไปให้ LINE -- ในที่นี้คือข้อความอย่างเดียว
      var formData = {
        'message': result,
      };
      
      // LIINE token : ได้มาจาก https://notify-bot.line.me/my/
      // ในตัวอย่างนี้ เป็นแบบ Personal
      var token = 'YOUR-TOKEN-GO-HERE'
      
      // POST แบบใน Token ใน Header ไปยัง LINE Notify REST API
      var options = {
        'method' : 'post',
        'headers' : {'Authorization': "Bearer "+token},
        'contentType': 'application/x-www-form-urlencoded',
        'payload' : formData
      }
      UrlFetchApp.fetch('https://notify-api.line.me/api/notify', options)
    }
    

    ตั้งชื่อ Project, Save แล้ว Run

    ** อย่าลืม ตั้งชื่อ Project แล้ว Save ด้วย

    จากนั้น กดปุ่ม Run เพื่อให้เกิดการขอ Authorization ตาม OAuth Scope

    ซึ่งจะเจอ Error นี้ ก็ไม่เป็นไร (เพราะไม่มี ข้อมูลส่งมาจริง ๆ นั่นเอง) ให้กด Dismiss ไป

    ไปตั้ง Trigger

    ไปที่ เมนู Edit > Current project’s triggers

    ตั้งค่า Trigger ให้ทำงานทันทีที่มีการ Submit แบบฟอร์ม

    Trigger คือการตั้งค่าให้ Script นี้ทำงานอัตโนมัติ เมื่อมีการ Submit แบบฟอร์ม

    คลิก Add Trigger แล้วเลือก Function “sendLineNotification” เลือก “on form submit” และ “Notify me immediately” เพื่อให้เมื่อมีการ Submit แบบฟอร์ม ก็จะแจ้งทาง LINE ทันที

    จากนั้น กดปุ่ม Save

    ผลที่ได้คืออย่างนี้

    ขั้นตอนการขอ LINE Token

    ไปที่เว็บไซต์

    https://notify-bot.line.me/my/

    แล้ว Login ด้วย LINE Account ของท่าน

    จากนั้น คลิกปุ่ม Generate token

    ตั้งชื่อ และ เลือกว่าจะ Notify ไปที่ใด เราสามารถเลือกได้ว่า

    • ให้ Notify ไปที่เราคนเดียว
    • ให้ Notify ไปยัง Group Chat

    *** เราต้องเพิ่ม Line Notify เป็นเพื่อนก่อน และ Invite เข้าไปใน Group Chat นั้น ๆ ด้วย

    จากนั้น คลิกปุ่ม Generate Token

    ก็จะได้ Token ให้คลิกปุ่ม Copy แล้วคลิก Close

    จากนั้น นำไปแทนที่ YOUR-TOKEN-GO-HERE ใน Google App Script ข้างต้น แล้ว Save

    เราสามารถสร้าง Token สำหรับใช้งานในกิจกรรมที่แตกต่างกันได้ หลาย ๆ อัน เช่น อาจจะมี ต้องการให้แจ้งเตือนในกลุ่มที่แตกต่างกันออกไป เป็นต้น

    เมื่อมีคน Submit แบบฟอร์ม ก็จะมี LINE แจ้งเตือน

    อันนี้ แบบ Basic ง่าย ๆ เดี๋ยวค่อยมาเล่าการใช้งานที่ซับซ้อนกว่านี้

    หวังว่าจะเป็นประโยชน์ครับ

  • PSU Webmail ทำไมลบ email ออกไปตั้งเยอะแล้ว แต่ Quota ยังเต็ม ?

    เหตุ: แบ่งเป็น 4 กรณี

    (1) ลบแล้ว แต่ยังไม่ Expunge

    ก่อนหน้านี้ เคยตั้งค่าให้ Delete แล้วก็ให้ลบหายไปเลย แต่ก็มีบางคน (หลายคน) แจ้งว่า อยากให้แค่ Mark Delete กล่าวคือ … ลบแล้ว แต่ให้เปลี่ยนใจได้ จึง … ทำให้คนอื่น ๆ เมื่อลบแล้ว ก็ต้องกดปุ่ม Expunge ด้วย เพื่อให้ลบถาวร

    *** ระบบ PSU Email เมื่อลบและกด Expunge แล้วจะเป็นการลบ ถาวร ไม่สามารถกู้คืนได้ไม่ว่ากรณีใด ๆ ***

    (2) ลบแต่จดหมายเล็ก ๆ

    บางที เราก็มีจดหมายไม่กี่ฉบับ แต่ว่า แต่ละฉบับ อาจจะแนบไฟล์ขนาดใหญ่ ๆ ทั้งนั้น วิธีการคือ สั่งให้ PSU Webmail แสดง ขนาดของ email แต่ละฉบับ โดยไปที่

    Options > Index Order

    จากนั้นคลิกปุ่ม Add ข้าง ๆ Size แล้ว คลิก Inbox อีกครั้ง

    จะปรากฏ Column “Size” ด้านขวามือ ให้คลิกเรียงลำดับ ตามขนาดของ email ให้เลือกลบฉบับที่มีขนาดใหญ่ ๆ ก่อน แล้ว *** และเมื่อลบแล้ว ก็อย่าลืม Expunge และ อย่าลืม เรียงลำดับใหม่ด้วย มิฉะนั้น จะไม่เห็นอีเมลใหม่สุด อยู่บนสุด *** เพราะระบบกำลังแสดงผลแบบเรียงลำดับตาม ขนาดของอีเมลอยู่

    (3) ลบใน Inbox หมดแล้ว แต่พื้นที่ยังเต็ม เป็นเพราะ มันเต็มใน Folder อื่น

    ให้คลิกที่ Folder Size ด้านล่างซ้ายของ PSU Webmail

    จะแสดงผลให้เห็นว่า จริง ๆ แล้ว Folder ใดที่กินพื้นที่ เมื่อทราบแล้ว ก็ไปจัดการให้ถูกที่

    (4) ทำตามข้อ 1-3 แล้ว ยังเต็ม ก็เป็นเพราะมี Folder “Trash” ซึ่งซ่อนอยู่

    มันมาได้ไง ?? มาจากการใช้ Mail Client บน โทรศัพท์มือถือ แล้วต่อ IMAP มายัง PSU Email Server มักจะสร้าง “Trash” Folder ไว้ เมื่อผู้ใช้ ลบอีเมล ก็จะย้ายไปไว้ใน Trash นี้ (ไม่ใช่ INBOX.Trash ของระบบ) ซึ่งจะมองเห็นได้บนโทรศัพท์มือถือ แต่ มักจะมองไม่เห็นบน PSU Webmail

    วิธีการแก้ไขคือ เลือกให้แสดง Folder นี้ โดยคลิกที่

    Folders > Trash > Subscribe

    แล้วกด Refresh folder list

    ก็จะปรากฏ Trash อยู่ในรายการด้าน ซ้ายมือ ให้ทำการลบได้ตามปรกติ

  • djsurvey – Google Forms Alternative #01

    ต่อจาก ddready – แพ็ครวม django + bootstrap4 + crispy form + docker พร้อมใช้งาน ในบทความนี้ ผมได้พยายามทำให้ใช้งาน Django ได้ง่ายขึ้น จนได้ แบบสำรวจอย่างง่าย พร้อมใช้งาน ใน 3 ขั้นตอน

    Prerequesite

    ติดตั้ง Python 3.6+ หรือ ใช้ Python Container แล้ว

    Repository

    https://github.com/nagarindkx/djsurvey

    ง่าย ๆ 3 ขั้นตอน

    1. Clone Repository

    ใช้คำสั่ง git

    git clone https://github.com/nagarindkx/djsurvey.git

    หรือ Download ไปก็ได้

    https://github.com/nagarindkx/djsurvey/archive/master.zip

    2. กำหนดข้อคำถามในแบบสำรวจ

    แก้ไขไฟล์

    /code/main/survey/models.py

    ตัวอย่างเช่น แบบสำรวจ ประกอบด้วย

    1. ชื่อ
    2. อีเมล
    3. เพศ
    4. วันเดือนปีเกิด
    5. ผลไม้ที่ชอบ
    6. ข้อเสนอแนะ

    ก็สร้าง Model ตามนี้ ( แรก ๆ อาจจะรู้สึกน่ากลัว แต่พอเข้าใจแล้ว มันง่ายมาก)

    from django.db import models
    class Survey(models.Model):
        fullname = models.CharField(
            verbose_name="ชื่อ",
            max_length=255,  blank=False)
        email = models.EmailField(
            verbose_name="อีเมล",
            blank=False)
        gender = models.CharField(
            verbose_name="เพศ",
            max_length=1,    blank=False,
            choices=[('F', 'หญิง'), ('M', 'ชาย')],
            default='F',
        )
        birthdate = models.DateField(
            verbose_name="วันเดือนปีเกิด",
            auto_now=False,  blank=False)
        fruit = models.CharField(
            verbose_name="ผลไม้ที่ท่านชอบ",
            max_length=1,    blank=False,
            choices=[('a', 'แอปเปิ้ล'), ('b', 'มะละกอ'),
                     ('c', 'กล้วย'), ('d', 'ส้ม')],
            default='c',
        )
        comment = models.TextField(
            verbose_name="ข้อเสนอแนะ",
            blank=True)

    แนะนำให้ใช้ Visual Studio Code จะทำงานได้ง่ายมาก

    3. Migrate แล้ว Run

    ใช้คำสั่งต่อไปนี้

    python manage.py migrate
    python manage.py runserver 0:8080

    ชมผลงาน

    http://localhost:8080/survey/

    หรือ ตกแต่งอีกนิดหน่อย ก็จะได้แบบนี้

    http://localhost:8080/advancedsurvey/

    สำหรับผู้ที่ใช้ Docker สามารถ ทำตามขั้นตอนใน แนวทางการพัฒนา Web Application ด้วย django จาก local docker สู่ Google Cloud Run เพื่อนำขึ้น Google Cloud Run ได้เลย (แต่ต้องเชื่อมกับ Database จริง ๆ ก่อนนะ – โปรดติดตามตอนต่อไป)

    คุณกำลังเจอปัญหาเหล่านี้อยู่ใช่ไม๊ ?

    • Google Forms ก็ง่ายดีแหล่ะ แต่ จะทำอย่างไรให้เก็บข้อมูลไว้ในฐานข้อมูลได้ ?
    • อยากให้ ผู้ใช้งาน Upload เอกสารเข้ามา / แก้ไขข้อมูล ซึ่ง Google Forms ก็ทำได้ แต่ต้อง Login ด้วย Google Account ก่อน จึงจะทำได้
    • Google Forms ก็ทำ Conditions ได้แหล่ะ (Go to section base on answer) แต่ ถ้าจะให้มีการคำนวนที่ซับซ้อนกว่านั้น ก่อนจะเลือกคำถามถัดไป จะทำอย่างไร ?

    ปัญหาเหล่านี้จะหมดไป เมื่อคุณใช้ Django !

    • ติดตั้งได้ บน Web Server ของคุณ!
    • Login ด้วย Facebook/Twitter/Google/Line หรือ Email หรือ จะเป็น Single Sign-On ก็ยังได้
    • ทุกอย่างสามารถ Customize ได้ ทำแบบสอบถามที่ซับซ้อนได้

    ไว้เจอกันในตอนต่อ ๆ ไปครับ

  • ddready – แพ็ครวม django + bootstrap4 + crispy form + docker พร้อมใช้งาน

    สำหรับใครที่อยากจะลองพัฒนา Web Application ด้วย django web framework ผมได้รวบรวมเป็นชุดเริ่มต้น ซึ่งจะสามารถสร้าง Responsive Web และ มีแบบฟอร์มที่สวยงามด้วย crispy form มาเรียบร้อย ใช้งานได้ทั้ง แบบ Python บนเครื่อง และ แบบ Docker ลองทำตามดูได้ครับ

    ต้นแบบ มี Bootstrap 4 พร้อมใช้งาน
    มี Login Form มาให้เลย
    เข้ามาในส่วนของ Profile และ Logout ได้

    Repository

    สามารถเปิด URL ต่อไปนี้ เพื่อไป Download หรือ จะใช้ git clone ก็ได้

    https://github.com/nagarindkx/ddready.git

    https://gitlab.psu.ac.th/kanakorn.h/ddready.git

    จากนั้น ให้เปิด cmd ไปยังตำแหน่งที่ clone ลงมา

    สำหรับผู้ที่ติดตั้ง python อยู่แล้ว

    แล้วใช้คำสั่งต่อไปนี้

    pip install -r requirements.txt
    cd code
    cd main
    waitress-serve --listen *:8080 main.wsgi:application

    สำหรับผู้ที่จะใช้ Docker

    บน Windows ใช้คำสั่งต่อไปนี้

    set PROJECTNAME="projectname"
    set GCP-PROJECT-ID="gcp-project-id"
    set SERVICE="service"
    docker build --rm -f "Dockerfile" -t %PROJECTNAME%:dev .
    docker run -d -v %CD%\code:/code -p 8080:8080 --name %PROJECTNAME% %PROJECTNAME%:dev
    docker exec -it %PROJECTNAME% /bin/sh -c "[ -e /bin/bash ] && /bin/bash || /bin/sh"

    ทดสอบใช้งาน

    http://localhost:8080

    ในตอนต่อไป จะแนะนำวิธีการสร้าง แบบสอบถาม ทดแทนการใช้ Google Forms ครับ

  • [Share and Tell] การพัฒนา Web Application ด้วย django ด้วย Docker และการนำไปใช้งานบน Google Cloud Run

    1.ชื่องานที่ทำ

    การพัฒนา Web Application ด้วย django ด้วย Docker และการนำไปใช้งานบน Google Cloud Run

    2.เป้าหมายของงานที่ทำ

    • เพื่อประยุกต์ใช้งาน Docker ในการพัฒนางาน ทำให้สามารถลดความไม่เข้ากันของรุ่นของซอฟต์แวร์ หรือ ไลบรารี่ในเครื่องพัฒนาได้
    • เพื่อผลักดันการทำงานแบบ Containerize ในองค์กร เป็นต้นแบบการลดความซ้ำซ้อนของการสร้างเซิร์ฟเวอร์แบบ Virtual Machine ทำให้เกิดการใช้งานทรัพยากรอยู่จำกัดให้มีประสิทธิภาพมากขึ้น
    • เพื่อเป็นต้นแบบการทำงานแบบ Serverless ด้วย Google Cloud Run
    • เพื่อเป็นต้นแบบการใช้งาน LINE Front-End Framework ในการทำ Chatbot

    3.สภาพแวดล้อมที่เกี่ยวกับงานที่ทำ

    • Operating System: Windows 10
    • Editor: Visual Studio Code
    • Environment: Docker Oriented
    • Programming Language: python
    • Web Framework: django + crispy form + bootstrap + jQuery
    • Mobile Development: LINE with LIFF (และถ้าเตรียมทัน จะแนะนำการพัฒนา Mobile Application ด้วย Google Flutter)
    • Database: postgresql, Google BigQuery
    • Machine Learning: Google Vision API

    4.บรรยายสรุปสั้น ๆ ว่า ต้องใช้อะไรบ้างและทำอย่างไร (ไม่ต้องลงขั้นตอนละเอียด)

    • ติดตั้ง Microsoft Visual Studio Code (VS Code) และ Docker Extension
    • ใช้ docker เพื่อ pull image ของ Environment ที่ต้องการมา สร้างเป็น Container แล้ว พัฒนาลงไปในนั้น โดยใช้วิธี Bind mount volume เข้าไป แล้วใช้ VS Code เขียน และทำงานผ่าน Attach Shell
    • ติดตั้ง Python Package ที่เกี่ยวข้อง ได้แก่ django + crispy form + bootstrap + jQuery
    • พัฒนา Web Application ด้วย django ตั้งแต่การสร้าง Data Model, สร้างแบบฟอร์ม รวมถึงการสร้าง RESTFul API และ การส่งข้อมูลไปให้ Google Vision API ทำงาน แล้วส่งผลกลับมา
    • พัฒนา LINE Front-End Framework เพื่อใช้เป็น User Interface แบบ Chatbot
    • (ถ้าเตรียมทัน) จะสาธิตการพัฒนา Mobile Application ด้วย Google Flutter

    5.อื่น ๆ อยากบอกอะไรเพิ่มเติม เขียนเพิ่มได้

    Man – a being in search of meaning.

    Plato, 429 BC
  • เค้าเอาไฟล์ MP4 บน Google Drive ไปแสดงใน Video Player บนเว็บได้อย่างไร

    สมมุติว่า เรามีไฟล์วิดีโอเป็น .mp4 อยู่ไฟล์หนึ่ง อยู่ใน Google Drive ต้องการเผยแพร่ เฉพาะบน Website ของเราเท่านั้น จะต้องทำอย่างไร?

    Javascript video player

    สิ่งแรกที่ต้องมีคือ ตัว Video Player บนเว็บ ลอง Google ด้วยคำว่า “javascript video player” ดู มีหลายตัวให้เลือกใช้ แต่ในที่นี้ ขอทดลองกับ video.js (เว็บไซต์ https://videojs.com )

    คลิกที่ USE NOW ( https://videojs.com/getting-started/ )

    จากนั้น ลองสร้างไฟล์ test.html โดยเอา Code จาก Video.js CDN ไปแปะเลย

    <head>
      <link href="https://vjs.zencdn.net/7.6.5/video-js.css" rel="stylesheet">
    
      <!-- If you'd like to support IE8 (for Video.js versions prior to v7) -->
      <script src="https://vjs.zencdn.net/ie8/1.1.2/videojs-ie8.min.js"></script>
    </head>
    
    <body>
      <video id='my-video' class='video-js' controls preload='auto' width='640' height='264'
      poster='MY_VIDEO_POSTER.jpg' data-setup='{}'>
        <source src='MY_VIDEO.mp4' type='video/mp4'> <!-- แก้ตรงนี้ -->
        <source src='MY_VIDEO.webm' type='video/webm'>
        <p class='vjs-no-js'>
          To view this video please enable JavaScript, and consider upgrading to a web browser that
          <a href='https://videojs.com/html5-video-support/' target='_blank'>supports HTML5 video</a>
        </p>
      </video>
    
      <script src='https://vjs.zencdn.net/7.6.5/video.js'></script>
    </body>

    จาก Code นี้ JavaScript จาะเรียกไฟล์ .MP4 จากไฟล์ชื่อ MY_VIDEO.mp4 ซึ่ง ถ้าเอา test.html นี้ไปวางบน Web Server ก็หมายความว่า เราต้องมีไฟล์ MY_VIDEO.mp4 ด้วย

    ไฟล์ MP4 บน Google Drive

    ตัวอย่างเช่น เราอาจอัดคลิปวิดีโอการสอน อยากจะเผยแพร่บนเว็บไซต์ของหน่วยงาน ผ่าน JavaScript Video Player อย่าง video.js ข้างต้น ก็สามารถทำได้ดังนี้

    1. แชร์ไฟล์ดังกล่าว ให้เป็น Anyone with the link can View
    2. แล้ว copy link นั้นมา หน้าตาประมาณนี้

      https://drive.google.com/open?id=FILE_ID
    3. จะเห็นคำว่า id= FILE_ID ตรงนี้ให้ Copy เก็บไว้

    แต่การที่เราจะเอา Link นี้ไปใช้ใน Video Player ตรง ๆ ไม่ได้ เพราะมันเป็นการเรียกใช้ Google Drive ไม่ใช่การเรียก File Content

    GoogleAPI

    วิธีการที่จะ Get Content ของไฟล์ที่ต้องการออกมากจาก Google Drive สามารถเรียกผ่าน Google API ซึ่ง หากจะทำเองก็สามารถทำได้ มีพวก node.js ให้ใช้งานอยู่ แต่พบว่า สามารถเรียกใช้ www.googleapis.com ได้ โดยอ้างอิงจาก https://googleapis.github.io/

    ในที่นี้ จะเรียกผ่าน Google Drive API ใน Version 3 รูปแบบ URL จะเป็นดังนี้

    https://www.googleapis.com/drive/v3/files/FILE_ID?alt=media&key=API_KEY

    ในการใช้งาน ต้องการ 2 ส่วน

    • FILE_ID ได้จากการแชร์ไฟล์ข้างต้น
    • API_KEY ได้มาจากการสร้าง Credential บน Google Cloud Platform วิธีการทำตามนี้ https://cloud.google.com/docs/authentication/api-keys

    การใช้งาน Google API นั้น มีส่วนทั้งที่ต้องจ่ายเงิน และส่วนที่ใช้ฟรี แต่ถูกจำกัด Quota ในกรณี Google Drive API สามารถใช้ได้ฟรี แต่จะมี Quota อยู่ โดยดูได้จาก https://developers.google.com/drive/api/v3/about-sdk

    ประกอบร่าง

    เมื่อได้ FILE_ID และ API_KEY มาแล้ว ก็เอาไปใส่ใน Code ข้างต้น

    <head>
      <link href="https://vjs.zencdn.net/7.6.5/video-js.css" rel="stylesheet">
    
      <!-- If you'd like to support IE8 (for Video.js versions prior to v7) -->
      <script src="https://vjs.zencdn.net/ie8/1.1.2/videojs-ie8.min.js"></script>
    </head>
    
    <body>
      <video id='my-video' class='video-js' controls preload='auto' width='640' height='264'
      poster='MY_VIDEO_POSTER.jpg' data-setup='{}'>
        <source src='https://www.googleapis.com/drive/v3/files/FILE_ID?alt=media&key=API_KEY' type='video/mp4'> <!-- เปลี่ยนตรงนี้ -->
        <source src='MY_VIDEO.webm' type='video/webm'>
        <p class='vjs-no-js'>
          To view this video please enable JavaScript, and consider upgrading to a web browser that
          <a href='https://videojs.com/html5-video-support/' target='_blank'>supports HTML5 video</a>
        </p>
      </video>
    
      <script src='https://vjs.zencdn.net/7.6.5/video.js'></script>
    </body>

    หวังว่าจะเป็นประโยชน์ครับ

    Disclaimer: จุดประสงค์ของบทความนี้ เพื่อแนะนำวิธีการทำเท่านั้น โปรดนำความรู้นี้ไปใช้งานอย่างสร้างสรรค์นะครับ ผู้เขียนบทความไม่เกี่ยวข้องใด ๆ กับผู้นำไปใช้ทั้งสิ้น

  • แนวทางการพัฒนา Web Application ด้วย django จาก local docker สู่ Google Cloud Run

    ในการพัฒนาแอพพลิเคชั่น เราก็จะเจอปัญหานึงเสมอ ๆ คือ เวอร์ชั่น (Version) ของเครื่องมือที่ใช้ในการพัฒนานั้น แต่ละโปรเจคมีความแตกต่างกัน เช่น ในกรณีของ การพัฒนา Web Application ด้วย django web framework เราอาจจะอยากใช้ python รุ่นล่าสุด คือ 3.8 แต่ในขณะเดียวกัน เมื่อหลังบ้านต้องการไปติดต่อ Tensorflow 2.0 ซึ่งยังต้องใช้งานกับ Python 3.6 เป็นต้น วิธีแก้ไขปัญหาทั่วไปคือ ติดตั้ง package ‘virtualenv’ เพื่อให้การพัฒนาแต่ละโปรเจค มี Environment แตกต่างกันได้

    แต่จากการใช้งานจริง พบว่า สุดท้าย ตอนเอาไป Production บนเครื่อง Server ก็ต้องตามไปติดตั้งเครื่องมือ และรุ่นที่ถูกต้อง แม้ใน Python จะมีคำสั่ง pip install -r requirements.txt ก็ตาม แต่ก็ยังไปติดปัญหาว่า OS ของเครื่องที่จะ Production นั้น รองรับรุ่นของเครื่องมืออีกหรือไม่ด้วย

    แนวทางการใช้ Container ด้วย Docker จึงเป็นที่นิยม เพราะ เมื่อเราพัฒนาเสร็จแล้ว สามารถ Pack เข้าไปใน Container แล้วเอาไป Deploy ได้ โดย (แทบจะ) ไม่ต้องกังวลกับ Environment ปลายทาง อีกทั้ง ยังสามารถทดสอบ Environment ใหม่ ๆ ก่อนจะ Deploy ได้ด้วย เช่นการเปลี่ยนรุ่นของ Python เป็นต้น

    ในบทความนี้ จะนำเสนอ แนวทางการสร้าง docker container เพื่อใช้เป็นฐานในการพัฒนา django และ สามารถต่อยอด ติดตั้ง package อื่น ๆ ตามต้องการ ตั้งแต่ Development ไปจนถึง Deployment สู่ Serverless Environment อย่าง Google Cloud Run

    สร้าง Development Container

    เริ่มจาก สร้างโฟลเดอร์ใหม่ขึ้นมา ในนั้นมี 2 ไฟล์ คือ Dockerfile และ requirements.txt กับ โฟลเดอร์ ชื่อ code

    Dockerfile

    • ใช้ image ของ python เป็นรุ่น 3.7-slim ซึ่งตัดส่วนที่ไม่จำเป็นออกแล้ว (ไม่ใช้ alpine เนื่องจาก พบรายงานว่า แม้จะมีขนาดเล็กกว่า แต่ถูกจำกัดทรัพยากรบางอย่าง ทำให้ทำงานได้ช้ากว่า)
    • สร้าง /code แล้วเข้าไปใช้พื้นที่นี้ (เหมือนคำสั่ง mkdir /code ; cd /code อะไรประมาณนั้น)
    • สั่งให้ copy ไฟล์ requirements.txt ไปใช้ที่ root ( / )
    • จากนั้น Upgrade คำสั่ง pip เป็นรุ่นล่าสุด แล้ว ติดตั้ง package ตามที่กำหนดใน requirements.txt
    • เปิด Port 8080 ไว้ เพื่อใช้ในการทดสอบ และเป็นไปในแนวทางเดียวกับการใช้บน Google Cloud Run ต่อไป
    FROM python:3.7-slim
    WORKDIR /code/
    COPY requirements.txt /
    RUN pip install -U pip \
        && pip install -r /requirements.txt
    EXPOSE 8080

    requirements.txt

    ในการพัฒนา django เมื่อทำการติดตั้ง package ใดเพิ่มเติมด้วยคำสั่ง pip install ก็จะบันทึกรายการ พร้อมรุ่นของ package มาในไฟล์นี้ ในที่นี้ ใช้ django, guincorn และ whitenoise เป็นหลัก (จะมีรายการ dependency ติดเข้ามาด้วย)

    Django==2.2.6
    gunicorn==19.9.0
    pytz==2019.3
    sqlparse==0.3.0
    whitenoise==4.1.4

    จากนั้นใช้คำสั่งต่อไปนี้ สร้าง (build) docker image จากไฟล์ Dockerfile ข้างต้น โดยมี option ที่เกี่ยวข้องดังนี้

    docker build --rm -f "Dockerfile" -t mydjango:dev .
    • –rm เมื่อ build แล้ว ก็ลบ container ชั่วคราวทิ้ง
    • -f กำหนดว่าจะเรียกจากไฟล์ใด วิธีนี้ มีประโยชน์ เวลาที่จะต้องมี Dockerfile ทั้ง Development และ Production ในโฟลเดอร์เดียวกัน ซึ่งจำเป็นต้องใช้ชื่อไฟล์ที่แตกต่างกัน
    • -t เป็นตั้งชื่อ docker image และ ชื่อ tag
    • . คือ ให้ build จากตำแหน่งปัจจุบัน

    ขั้นตอนนี้จะได้ docker image ชื่อ mydjango และมี tag เป็น dev แล้ว้

    (ในที่นี้ พัฒนาบนเครื่องคอมพิวเตอร์ที่เป็น Windows 10 ซึ่ง %CD% จะให้ค่า Current Directory แบบ Absolute path ออกมา เช่นเดียวกับบน Linux ที่ใช้ $(pwd) )

    ต่อไป สั่ง run ด้วยคำสั่ง และ options ดังต่อไปนี้

    docker run --rm -it -p 8080:8080  -v %CD%\code:/code  mydjango:dev bash
    • –rm เมื่อจบการทำงาน ก็ลบ container ชั่วคราวทิ้ง
    • -it คือ interactive และเปิด TTY
    • -p เพื่อเชื่อม port 8080 จากภายนอก เข้าไปยัง port 8080 ภายใน container
    • -v เพื่อเชื่อม Volume หรือโฟลเดอร์ของเครื่อง host กับ /code ภายใน container ขั้นตอนนี้สำคัญ
    • bash ข้างท้าย เพื่อส่งคำสั่ง เรียก bash shell ขึ้นมา ซึ่งจะสัมพันธ์กับ -it ข้างต้น ทำให้สามารถใช้งาน shell ภายใน container ได้เลย

    ผลที่ได้คือ bash shell และ อยู่ที่ /code ภายใน container

    root@757bcbb07c7f:/code#

    ตอนนี้ เราก็สามารถสร้าง django ได้ตามปรกติแล้ว (คลิกดูตัวอย่างเบื้องต้น) แต่ในตัวอย่างนี้ จะเริ่มจากการสร้าง project ชื่อ main เพื่อใช้ในขั้นตอนต่อไป ด้วยคำสั่งต่อไปนี้

    django-admin startproject main
    cd main

    ในระหว่างการพัฒนา สามารถใช้คำสั่ง runserver โดยเปิด Port 8080 ใน container เพื่อทดสอบได้ดังนี้ (สอดคล้องตามที่อธิบายข้างต้น)

    python manage.py runserver 0.0.0.0:8080

    สร้าง Production Docker Image

    คำสั่งข้างต้น สามารถใช้ได้เฉพาะขั้นตอนการพัฒนา แต่เมื่อพัฒนาเสร็จแล้ว ควรใช้ Application Server แทน ในที่นี้จำใช้ gunicorn แต่ก่อนอื่น จะต้องปรับ Configuration ของ django ให้พร้อมในการ Deployment ก่อน

    main/settings.py

    # แก้ไข
    DEBUG = False
    ALLOWED_HOSTS = ['localhost','SERVICE-ID.run.app']
    
    # เพิ่ม
    MIDDLEWARE = [
        ...
        # Whitenoise
        'whitenoise.middleware.WhiteNoiseMiddleware',
        ...
    ]
    # เพิ่ม
    STATIC_ROOT = os.path.join(BASE_DIR, 'static')

    มีเพิ่มเติมคือ whitenoise ซึ่งเป็น package สำหรับจัดการเกี่ยวกับการให้บริการ static file ในตัว มิเช่นนั้นจะต้องไปตั้งค่าใน Web Server ให้จัดการแทน

    เมื่อเราตั้งค่า DEBUG = False จะต้องกำหนด ALLOWED_HOSTS เสมอ ในที่นี้กำหนดให้เป็น localhost และ Production URL (SERVICE-ID.run.app) ที่จะเกิดขึ้นเมื่อสร้าง Service บน Google Cloud Run ครั้งแรกไปแล้ว (ค่อยกลับมาแก้ไขแล้ว Revision อีกครั้ง)

    ใช้คำสั่งต่อไปนี้เพื่อรวบรวม static files ต่าง ๆ มาไว้ในที่เดียวกัน ในที่นี้ คือที่ โฟลเดอร์ static

    python manage.py collectstatic

    ทดสอบ Production ด้วย gunicorn ด้วยคำสั่งต่อไปนี้

    gunicorn --bind 0.0.0.0:8080 main.wsgi

    ทดสอบเรียก Local Admin Console ( http://localhost:8080/admin ) ดู ถ้าเรียก static file เช่นกลุ่ม css ได้ ก็พร้อมสำหรับจะนำขึ้น Google Cloud Run ต่อไป

    สุดท้าย สร้าง Production Dockerfile และ สรุป requirements.txt ดังนี้

    Dockerfile.production

    FROM python:3.7-slim
    WORKDIR /code
    COPY ./code/* ./
    RUN pip install -U pip \
        && pip install -r requirements.txt
    EXPOSE 8080
    CMD [ "gunicorn","--bind","0.0.0.0:8080", "main.wsgi"]

    requirements.txt

    pip freeze > requirements.txt

    จากนั้น ใช้คำสั่งต่อไปนี้ เพื่อสร้าง Production Docker Image (ออกมาจาก Development Container shell ก่อน) โดยจะใช้ tag เป็น latest

    docker build -t mydjango:latest -f "Dockerfile.production" .

    ส่ง Production Docker Image ขึ้น Google Container Registry

    Google Cloud Run จะเรียกใช้ docker image ที่อยู่บน Google Container Registry เท่านั้น

    • เปิด Google Console
    • สร้าง Project ใหม่ และ ตั้งค่า Billing
    • เปิดใช้งาน Google Cloud Run และ Google Container Registry
    • ติดตั้อง Google Cloud SDK เพื่อให้สามารถ push ขึ้นได้ และ ยืนยันตัวตนด้วย Google Account

    แล้วใช้คำสั่งต่อไปนี้ เพื่อ tag

    docker tag mydjango:latest gcr.io/YOUR-GCP-PROJECT-ID/SERVICE-NAME
    • YOUR-GCP-PROJECT-ID เป็น Project ID ที่สร้างขึ้น
    • SERVICE-NAME ชื่อ service ที่จะสร้าง

    แล้วก็ push ขึ้น Google Container Registry

    docker push gcr.io/YOUR-GCP-PROJECT-ID/SERVICE-NAME

    สร้าง Google Cloud Run Service

    สร้าง Service โดยเลือก Image ที่ต้องการ

    เมื่อเสร็จแล้วจะได้ URL อย่าลืมเอาไปแก้ไขใน main/settings.py ในส่วนของ ALLOWED_HOSTS แทน SERVICE-ID.run.app

    จากนั้น build, tag และ push ขึ้น Google Cloud Registry อีกครั้ง แล้ว Deploy New Revision เป็นอันเรียบร้อย

    อันนี้เป็นการ Proof of Concept ในบทความต่อไป จะนำเสนอตัวอย่างการใช้งานจริงครับ

  • วิธีการระบบการจองตั๋ว (Ticket Reservation System ) alf.io

    ALF.io เป็น Open Source Ticket Reservation System แบบ Web Application

    • ผู้ดูแลระบบสามารถสร้าง Event อย่างเช่นงานประชุมสัมนา เมื่อเปิดรับลงทะเบียนเข้าร่วมงานได้ (แบบเก็บเงินหรือฟรีก็ได้) กำหนดจำนวนที่นั่งได้
    • ผู้เข้าร่วมงานกรอกข้อมูลส่วนตัว (และชำระเงินก็ได้)
    • ระบบจะส่ง Ticket ไปให้ทาง Email ในรูปแบบ QR Code
    • เมื่อถึงวันงาน เจ้าหน้าที่ที่หน้างานติดตั้ง Application บน Smartphone ของตนเอง (ซึ่งต้องลงทะเบียนกับระบบ)
    • ผู้เข้าร่วมงานแสดง QR ของตนเองให้เจ้าหน้าที่ Scan ได้เลย

    วิธีการติดตั้ง

    ต่อไปนี้ เป็นวิธีการติดตั้ง alf.io รุ่น 2.0-M1-1909 บน Windows 10 Education และ Windows Server 2016

    Prerequisite

    1. Java JDK
      เนื่องจาก alf.io พัฒนาด้วย Java รุ่น 12 จึงแนะนำให้ติดตั้ง Oracle JAVA SE รุ่นล่าสุด (ปัจจุบันคือ Java SE 13) โดยสามารถ download จาก Link นี้
      https://www.oracle.com/technetwork/java/javase/downloads/index.html
    2. Database Server
      สำหรับ Database แนะนำให้ใช้ Postgresql (ปัจจุบัน รุ่นล่าสุดคือ รุ่น 11) จากนั้น
      – สร้าง Database ชื่อ alfio
      – User ชื่อ alfio ให้สามารถสิทธิ์ CREATE ได้ โดยสามารถ Download จาก Link นี้
      https://www.postgresql.org/download/windows/

    ขั้นตอนการติดตั้ง

    1. สร้าง Folder
      เช่น C:\alfio เป็นต้น
    2. Download alf.io
      จาก https://github.com/alfio-event/alf.io/releases/tag/2.0-M1-1909
      เลือกไฟล์ชื่อ alfio-2.0-M1-1909-boot.war
      เก็บไว้ใน Folder ที่สร้างขึ้น (ในที่นี้ C:\alfio)
    3. สร้างไฟล์ Configuration
      สร้างไฟล์ชื่อ application.properties เพื่อกำหนดค่าเกี่ยวกับ Database ได้แก่ Host, Database, User, Password และอื่น ดังตัวอย่าง (อย่าลืมเปลี่ยน Password ให้ตรงกับที่ตั้งไว้)
    datasource.dialect=PGSQL
    datasource.driver=org.postgresql.Driver
    datasource.url=jdbc:postgresql://localhost:5432/alfio
    datasource.username=alfio
    datasource.password=ALFIO_PASSWORD_HERE
    datasource.validationQuery=SELECT 1
    spring.profiles.active=dev

    Run !

    ด้วยคำสั่ง

    java -jar alfio-2.0-M1-1909-boot.war

    หน้า Event

    http://localhost:8080/

    หน้า Admin

    http://localhost:8080/admin

    ตัวอย่างการใช้งาน

    https://ticket.psu.ac.th/event/KPC2019/

    เมื่อ Admin ของงาน (แต่ละ Server มีได้หลาย Event) สร้าง Ticket ให้ หรือ ผู้สนใจเข้าร่วมงาน เข้ามาสมัครร่วมงานเองก็ได้ จะได้ Email แจ้งดังนี้

    ซึ่งจะมี QR Code แนบมา (ที่เห็นเป็น # เพราะยังไม่ได้ใส่ Font ภาษาไทยในการ Generate PDF ให้ถูกต้อง — ไว้ค่อยเล่าให้ฟัง)

    เมื่อถึงวันงาน เจ้าหน้าที่รับลงทะเบียน จะติดตั้ง Application ลงใน Smartphone ของตนเอง แล้วมีการสร้าง Account เพื่อรับ Check-in (ค่อยมาลงรายละเอียด)

    ก็สามารถคลิกที่ Scan Attendees QR Code ของผู้มาลงทะเบียนเข้างานได้เลย

    หวังว่าจะเป็นประโยชน์ครับ

  • Google Drive กับ Google Share Drive — กินพื้นที่ใคร ?

    ปัญหา: การแชร์พื้นที่จาก Google Drive กับ Google Share Drive นั้น เมื่อผู้ใช้ที่เราแชร์ไปให้ ทำการ Upload ไฟล์ขึ้นมา จะกินพืันที่ของใคร ?

    มาทดลองกัน

    Google Drive

    User A สร้าง Folder ชื่อ “Test Upload” บน “Google Drive” แล้วแชร์ให้ User B สามารถแก้ไขได้ (edit)

    User B เปิด Google Drive ของตนเอง แล้วเข้าไปใน Shared With Me ก็จะเห็น “Test Upload”

    User B ทำการ Upload File จากนั้น ไปดูใน Detail จะพบว่า ไฟล์มีขนาด 945 KB และ ใช้พื้นที่ของตัวเองไป 945 KB ด้วย

    กลับมาดูใน Google Drive ของ User A ซึ่งเป็นเจ้าของ (Owner) โฟลเดอร์ “Test Upload” พบว่า ไม่ได้ใช้ Quota พื้นที่จัดเก็บของ User A เลย เพราะ เจ้าของไฟล์ (File) คือ User B

    และ แม้ User A จะเป็นเจ้าของ Folder ก็ทำได้เพียงแต่ เตะ User B ไม่ให้เห็น Folder แต่ ไม่สามารถ ถอนสิทธิ์ความเป็นเจ้าของ ของ User B ได้ (เศร้า)

    Google Share Drive

    ก่อนหน้านี้เรียกว่า Team Drive แต่เปลี่ยนชื่อเป็น Share Drive ซึ่ง เป็น Feature ของ G Suite for Education (และ G Suite ตามที่ Google กำหนด) มีสิทธิ์ สร้าง Share Drive

    ผู้ใช้ขององค์กร (ในที่นี้คือ มหาวิทยาลัยสงขลานครินทร์) สามารถสร้าง Google Share Drive แล้ว Add Member เป็นผู้ใช้ที่ใช้ Google Account อื่น (รวมถึง Gmail ด้วย) เข้ามาใช้งานร่วมกันได้ โดย ความเป็นเจ้าของ Share Drive คือ องค์กร กล่าวคือ แม้ User A จะเป็นคนสร้าง

    ต่อไป User A ทำการสร้าง Share Drive ตั้งชื่อว่า “Test Share Drive”

    แล้วเพิ่ม User B มาเป็น Member ให้สิทธิ์เป็น Contributor (สิทธิ์ใน Share Drive จะมีหลายระดับกว่า Google Drive)

    User B จะเห็น Share Drive จาก เมนู “Shared drives” (แต่ถ้า share จาก Google Drive จะเห็นใน “Shared with me”)

    เมื่อ User B ทำการ Upload ไฟล์เข้าไป จะพบว่า ไม่ใช้ Quota พื้นที่ User B เลย!!

    ต่อมา User A เตะ User B ออกไป

    ไฟล์ยังอยู่ในองค์กร ของ User A

    ส่วน User B ก็เข้าถึงไม่ได้อีกต่อไป

    สรุป

    • Google Drive สิทธิ์เป็นของ Owner และใช้พื้นที่ของผู้เป็น Owner ดังนั้น แม้ Google Drive ขององค์กร จะ Unlimited แต่ เวลาที่ผู้ใช้จาก Free Gmail Upload ไฟล์ขึ้นมา ก็จะใช้ Quota พื้นที่ของ Free Gmail คือ 15 GB นั้น !! ดังนั้น วิธีนี้ จะไม่สามารถให้ ผู้ใช้ Free Gmail Upload ไฟล์ที่มีขนาดเกิน Available Quota ของตนเองได้
    • Shared Drive สิทธิ์เป็นขององค์กร เวลา Free Gmail Upload ขึ้นมา จะไม่กิน Quota พื้นที่เค้า และ องค์กรสามารถเตะ Free Gmail ออกไปได้

    เข้าใจตรงกันนะ