2022年9月28日 星期三

只要點兩下,就能寄送全班個人成績單

        最近段考剛過,又要通知家長學生成績。原本讓學生寫聯絡簿,然後將紙本成績單貼上聯絡簿,家長在聯絡簿與紙本成績單上簽名,導師批閱聯絡簿與紙本成績單就可以知道家長是否知情。但是,學生會仿冒家長簽名或拿家長的印章蓋章,阻止家長得知成績。老師必須要比對筆跡,才能知道學生是否仿冒家長簽名。
        由於法規限制,家長只能收到自己孩子的成績,不能知道班上其他學生的成績。老師會從學校方面取得紙本全班成績單或從雲端校務系統下載電子全班成績單。換言之,老師要讓家長知道自己孩子的成績,就得對紙本全班成績單做處理,將之一一切割成紙本個人成績單。或是重新整理電子全班成績單,將之複製貼上到個人成績單。總之,這是一項大工程。
        是否能夠開發程式,讓老師只要點兩下就能夠建立全班個人成績單。接下來,點兩下就能夠將個人成績單一一發送到家長電子信箱。
        最後完成程式:
下載檔案。解壓密碼:demo1234
教學影片:


        以下是使用教學,共有五個步驟:
一.若沒有Gmail,請先建立自己的Gmail
二.下載程式與解壓縮
三.設定寄件者電郵與密碼
四.自雲端校務系統下載report.xlsx
五.對著01建立學生成績PDF_PyScroeTablePdf.exe點兩下
六.對著02批次寄電郵給家長_PythonGmail.exe點兩下
        
        依序如下:
一.若沒有Gmail,請先建立自己的Gmail
        一次設定




二.下載程式與解壓縮
      解壓縮時,要注意:不能破壞資料夾結構。





.設定寄件者電郵與密碼
        一次設定
        程式預設使用Gmail。若沒有Gmail,請建立Gmail。
        設定兩步驟驗證


        設定 應用程式密碼



.自雲端校務系統下載report.xlsx

.對著01建立學生成績PDF_PyScroeTablePdf.exe點兩下

.對著02批次寄電郵給家長_PythonGmail.exe點兩下

程式設計部分:
程式目的:讀取report.xlsx 並整理全班學生成績匯出學生個人成績.pdf  到 附件資料夾
檔案名稱:PyScroeTablePdf.py
檔案內容:
import os
import openpyxl as opxl
from win32com.client import DispatchEx

class StudentDataDict():
    def __init__(self,FileName):
        self.FileName = FileName

    def StudentData(self):
        #取得學生成績資料
        wb = opxl.load_workbook(self.FileName)
        wbsh = wb['Worksheet']
        StudentDataDict = dict()
        ScoreName = wbsh.cell(1,1).value
        StudentDataDict[1] = ScoreName
        SubjectNameList = []
       
        for i in range(1,wbsh.max_column+1):
            SubjectNameList.append(wbsh.cell(2,i).value)
        StudentDataDict[2] = SubjectNameList
       
        for j in range(3,wbsh.max_row+1):
            StudentDataList = []
            for i in range(1,wbsh.max_column+1):
                StudentDataList.append(wbsh.cell(j,i).value)
            StudentDataDict[j] = StudentDataList

        return StudentDataDict

class ScoreTablePdf():
    def __init__(self,StudentData):
        self.StudentData = StudentData

    def RecipientData(self):
        #建立收件者資料
        RecipientFile = str(os.path.abspath(os.getcwd()))+'\\收件者資料.xlsx'
        TempStudentData = self.StudentData
        if not os.path.exists(RecipientFile):
            print("建立收件者資料.xlsx.......")
            #收件者資料.xlsx不存在,則自動建立收件者資料.xlsx
            TempExcelFile = opxl.Workbook()
            TempExcelFileSheet = TempExcelFile.active
            TitleName = ['年班座號','學生姓名','家長姓名','家長電郵','附件名稱','附件副檔名']
            for i in range(0,len(TitleName)):
                TempExcelFileSheet.cell(row=1,column=i+1).value = TitleName[i]
            for j in range(0,len(TempStudentData)):
                TempExcelFileSheet.cell(row=j+2,column=1).value = TempStudentData[j+3][0]+str(TempStudentData[j+3][1]).zfill(2)
                TempExcelFileSheet.cell(row=j+2,column=2).value = TempStudentData[j+3][3]
                TempExcelFileSheet.cell(row=j+2,column=5).value = TempExcelFileSheet.cell(row=j+2,column=1).value
                TempExcelFileSheet.cell(row=j+2,column=6).value = 'pdf'
            TempExcelFile.save(RecipientFile)    
            print("建立收件者資料.xlxs OK")
           
    def ScoreTable(self):
        TempPath = str(os.path.abspath(os.getcwd()))+'\\Temp\\'
        if not os.path.isdir(TempPath):
            os.mkdir(TempPath)
        AttachPath = str(os.path.abspath(os.getcwd()))+'\\附件\\'
        if not os.path.isdir(AttachPath):
            os.mkdir(AttachPath)
        TempStudentData = self.StudentData    
        TableSubject = self.StudentData[1]
        TempStudentData.pop(1)
        TestSubject = self.StudentData[2]
        TempStudentData.pop(2)
        for i in TempStudentData:
            ExcelWorkBook = opxl.Workbook()
            ExcelSheet = ExcelWorkBook.worksheets[0]
            ExcelSheet['A1'] = TableSubject
            for j in range(1,len(TestSubject)):
                ExcelSheet.cell(row=j+1,column=1).value = TestSubject[j]
                ExcelSheet.cell(row=j+1,column=2).value = TempStudentData[i][j]
            ExcelFileName = TempStudentData[i][0]+str(TempStudentData[i][1]).zfill(2)+".xlsx"    
            ExcelWorkBook.save(TempPath+ExcelFileName)
            PdfFileName = TempStudentData[i][0]+str(TempStudentData[i][1]).zfill(2)+".pdf"    
            TempExcelApplication = DispatchEx("Excel.Application")
            TempExcelApplication.Visible = False
            TempExcelApplication.DisplayAlerts = 0
            TempBooks = TempExcelApplication.Workbooks.Open(TempPath+ExcelFileName,False)
            TempBooks.ExportAsFixedFormat(0,AttachPath+PdfFileName)
            TempBooks.Close(False)
            print("建立學生 "+PdfFileName+" 成績單...OK")
            os.remove(TempPath+ExcelFileName)
        os.removedirs(TempPath)
       

print("取得report.xlsx 資料....")
pep01 = StudentDataDict('report.xlsx').StudentData()
print("取得report.xlsx 資料OK")
print("建立全班學生個人成績單.....")
ScoreTablePdf(pep01).ScoreTable()
print("建立全班學生個人成績單OK")
ScoreTablePdf(pep01).RecipientData()
os.system("pause")
os.system("exit")

程式設計部分:
程式目的:將附件內的學生個人成績.pdf 依著收件者資料.xlsx 一一寄給家長
檔案名稱:PythonGmail.py
檔案內容:
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
import smtplib
from email.mime.image import MIMEImage
from pathlib import Path
from email.mime.application import MIMEApplication
import os
import openpyxl as opxl

           
class EmailOpenFiles():
    #開啟檔案
   
    def __init__(self,DirectoryName,FileName):
        self.DirectoryName = DirectoryName
        self.FileName = FileName

    def AttachFiles(self):
        #取得附件資料夾內所有檔案名稱並回傳List
        AttachDirPath=str(os.path.abspath(os.getcwd()))+'\\'+self.DirectoryName+'\\'
        AttachFileNameList = os.listdir(AttachDirPath)
        return AttachFileNameList
   
    def EmailFileContent(self):
        #設定信件內容檔名並取得檔案內容並回傳List
        EmailContentFileName = str(os.path.abspath(os.getcwd()))+"\\"+self.FileName
        EmailContentFile = open(EmailContentFileName,'r')
        EmailContentList = EmailContentFile.readlines()
        EmailContentFile.close()
        return EmailContentList
   
    def AttachDirPath(self):
        #取得附件資料夾路徑
        AttachDirPath=str(os.path.abspath(os.getcwd()))+'\\'+self.DirectoryName+'\\'
        return AttachDirPath
   
    def AttachExcelOpen(self):
        #打開附件為Excel檔案並回傳List
        AttachExcelFileName = str(os.path.abspath(os.getcwd()))+"\\"+self.FileName
        TempExcelWorkBook = opxl.load_workbook(AttachExcelFileName)
        TempMax_Row = TempExcelWorkBook.worksheets[0].max_row
        TempMax_Column = TempExcelWorkBook.worksheets[0].max_column
        TempReturnList = []
        for i in range(1,TempMax_Row+1):
            TempList = []
            for j in range(1,TempMax_Column+1):
                TempList.append(TempExcelWorkBook.worksheets[0].cell(i,j).value)
            TempReturnList.append(TempList)
        return TempReturnList



class PythonGmail():
    def __init__(self,EmailSubject,EmailFrom,EmailTo,EmailContent,EmailAttachments,EmailSender,EmailPass):
        self.EmailSubject = EmailSubject
        self.EmailFrom = EmailFrom
        self.EmailTo = EmailTo
        self.EmailContent = EmailContent
        self.EmailAttachments = EmailAttachments
        self.EmailSender = EmailSender
        self.EmailPass = EmailPass
   
    def PythonGmail(self):
        #建立MIMEMMultipart物件
        content = MIMEMultipart()
        #郵件標題
        content["subject"] = self.EmailSubject
        #寄件者Email
        content["from"] = self.EmailFrom
        #收件者Email
        content["to"] = self.EmailTo
        #郵件內容
        content.attach(MIMEText(self.EmailContent))
       
        #附件寄送檔案
        AttachFileName = self.EmailAttachments
        AttachFileload = MIMEApplication(open(AttachFileName,'rb').read())
        AttachFileload.add_header('Content-Disposition','attachment',filename=AttachFileName)
        content.attach(AttachFileload)
       
        #設定SMTP伺服器
        with smtplib.SMTP(host="smtp.gmail.com",port="587") as smtp:
            try:
                #驗證SMTP伺服器
                smtp.ehlo()
                #建立加密傳輸
                smtp.starttls()
                #登入寄件者Gmail
                #smtp.login("寄件者信箱","寄件者密碼")
                smtp.login(self.EmailSender,self.EmailPass)
                #寄送郵件
                smtp.send_message(content)
                #顯示訊息
                return "Success! Send OK!"
            except Exception as e:
                return "Error message:"+str(e)

#取得附件資料夾內所有檔案名稱
EmailAttachments = EmailOpenFiles('附件','').AttachFiles()
#取得附件資料夾的絕對路徑
EmailAttachDirPath = EmailOpenFiles('附件','').AttachDirPath()

#取得信件標題檔案內容並存成信件標題list
EmailSubjectlist = EmailOpenFiles('','信件標題.txt').EmailFileContent()
#從信件標題list取得信件標題字串
EmailSubject = EmailSubjectlist[0]

#取得信件內容檔案內容並存成信件內容list
EmailContentlist = EmailOpenFiles('','信件內文.txt').EmailFileContent()
#從信件內容list取得信件內容字串
EmailContent = ""
for i in EmailContentlist:
    EmailContent = EmailContent + i

#從寄件者電郵與密碼.txt取得List
EmailSenderAddrList = EmailOpenFiles('','寄件者電郵與密碼.txt').EmailFileContent()
#去除List[0]標題
EmailSenderAddrList.pop(0)
#取得寄信者email與密碼
EmailSender,EmailPass = EmailSenderAddrList[0].split(',')

#從收件者資料.xlsx 取得List
EmailToList = EmailOpenFiles('','收件者資料.xlsx').AttachExcelOpen()
#去除List[0]標題
EmailToList.pop(0)
#取得收件者資料並逐一寄信
for i in EmailToList:
    A1,A2,A3,A4,A5,A6 = i
    EmailAttachFileName=EmailAttachDirPath+A5+'.'+A6
    EmailTest=PythonGmail(EmailSubject,EmailSender,A4,EmailContent,EmailAttachFileName,EmailSender,EmailPass).PythonGmail()
    print(A1+" "+A2+" Email "+ EmailTest)

os.system("pause")
os.system("exit")



資料來源:
1.Python實現Gmail客製化信件大量發送 — 【基礎篇】
2.Python 初學第十二講—檔案處理
3.Python split 字串分割用法與範例




2022年9月27日 星期二

APPLE IPAD 管理與派送APP 筆記

一、觀念:
1.行動裝置管理MDM
Mobile Device Management
 
2.Apple 學校管理 ASM(購買APP)
Apple School Manager
 
3.Jamf pro (管理IPAD與派送APP) 
學校不用架設伺服器來管理IPAD
管理網址:https://twmoechc學校教育部代碼.jamfcloud.com

二、購買APP並派送到IPAD
1.購買APP
   輸入之後,第一次需要做手機認證。
   注意事項:廠商會協助辦理,但資料須由學校承辦人填寫。
   登入之後,選App
   以Line為例,
 
2.Jamf pro 將App派送到IPAD:
管理網址:https://twmoechc學校教育部代碼.jamfcloud.com
 注意事項:帳密忘記->詢問廠商。
 

 

 
 

 
 
 


2022年9月15日 星期四

如何跨年度,持續使用二林國小紀明村老師的運動會競賽檢錄系統

整理:
1.只要會用滑鼠點兩下,用shell 在 ubuntu 16.04 x64 桌面版本快速安裝 運動檢錄系統
https://skjhcreator.blogspot.com/2021/03/shell-ubuntu-1604-x64.html
2.紀明村老師運動會競賽檢錄系統更新模組_學生帳號管理模組
https://skjhcreator.blogspot.com/2021/03/blog-post.html
3.二林國小紀明村老師的二林網管 PDO + SQLite 程式寫作工具箱2014.07
https://skjhcreator.blogspot.com/2021/03/pdo-sqlite-201407.html
4.用shell 在CentOS 7 minimal 64位元 安裝 紀明村老師的運動會檢錄系統
https://skjhcreator.blogspot.com/2021/02/shell-centos-7-minimal-64.html
5.紀明村老師的運動檢錄系統程式碼研究心得(一)介接CloudSchool與mysql資料庫
https://skjhcreator.blogspot.com/2021/03/cloudschoolmysql.html
6.紀明村老師運動檢錄系統程式碼研究心得(二)登入login登出logout與使用者認證
https://skjhcreator.blogspot.com/2021/02/loginlogout.html
7.紀明村老師運動檢錄系統程式碼研究心得(三)smarty
https://skjhcreator.blogspot.com/2021/02/smarty.html


        感恩二林國小紀明村老師開發運動檢錄系統
第一版Sport1090730.zip
        感恩二林國小紀明村老師提供解答
        又到了新學年的第一個學期,每當這個時候,體育組就要開始籌備運動會相關事宜。但是問題來了,去年運動會已經建置好運動會競賽檢錄系統。那今年運動會競賽檢錄系統更新事宜要怎麼做?現在打開運動會競賽檢錄系統,資料還是去年的。要怎麼做,才能更新資料庫?
環境介紹:
          (1)系統建置在 CentOS 裡 /var/www/html/Sport109/
          (2)資料庫位置 /var/www/Sport_data/

更新資料庫的做法:
1.修改/var/www/html/Sport109/109.conf.php 
   將原先的 $DB='sport109.sqlite3'; 加上註解 //
   另外新增$DB='sport2022.sqlite3';
   如下圖:

2.重新自雲端校務系統抓取資料:
在瀏覽器上網址打上: https://伺服器IP/Sport109/easy.php
就會看到

按下上圖中紅色箭頭所指處<<按下後開始>>。如下圖,就可以看到資料庫已經更新了。

Laravel 12 Model 資料庫中的資料表,並提供與資料庫互動的介面

相關系列文章: 1. 在 windows 10 安裝 laravel 12 studentManagement環境與設定 2. laravel 12 route 路由 3. laravel 12 Blade Templates 網頁模版 4. laravel 12 Control...