gdoc #1

Merged
a2nr merged 5 commits from gdoc into master 2024-03-15 20:37:22 +07:00
13 changed files with 446 additions and 174 deletions

4
.gitignore vendored
View File

@ -1,3 +1,3 @@
client_secrets.json
client_secret.json
token.json
__pycache__/
__pycache__/

View File

@ -1,102 +0,0 @@
# coding: utf-8
from __future__ import unicode_literals
import sys, os
import requests
import importlib
# to run separatly from soffice
# $ soffice --calc --accept="socket,host=localhost,port=2002;urp;StarOffice.ServiceManager"
# uncomemnt for run separatly from soffice
# sys.path.append("/lib64/libreoffice/program/")
from scriptforge import ScriptForge, CreateScriptService
from unohelper import fileUrlToSystemPath
#[start] comment for run separatly from soffice
if (not 'gquiz' in sys.modules) or (not 'moodleQuiz' in sys.modules):
doc = XSCRIPTCONTEXT.getDocument()
url = fileUrlToSystemPath('{}/{}'.format(doc.URL,'Scripts/python/Library'))
sys.path.insert(0, url)
else:
importlib.reload(gquiz)
importlib.reload(moodleQuiz)
#[end]
#[start] uncomemnt for run separatly from soffice
#sys.path.insert(0, '{}/{}'.format(os.getcwd(),'Library'))
#ScriptForge(hostname='localhost', port=2002)
#[end]
from gquiz import gquiz
from moodleQuiz import moodleQuiz
ui = CreateScriptService("UI")
doc = CreateScriptService("Calc")
bas = CreateScriptService("Basic")
def MakeTemplate():
doc.SetArray(doc.CurrentSelection, \
(("<Text question>","<IMG question image>", \
"<isAnswerA>", "<IMG option1>", "<Text Option1>", \
"<isAnswerB>", "<IMG option2>", "<Text Option2>", \
"<isAnswerC>", "<IMG option3>", "<Text Option3>", \
"<isAnswerD>", "<IMG option4>", "<Text Option4>", \
"<isAnswerE>", "<IMG option5>", "<Text Option5>", ),))
def _statusBarInfoUpdate(text : str, progress : int):
ui.SetStatusbar("{}% {}".format(progress,text), progress)
def _updateQuestion(q):
selctedCell = doc.CurrentSelection
cwd = os.getcwd()
maxRow = doc.LastRow(selctedCell)+1-doc.FirstRow(selctedCell)
for nrow in range(0, maxRow):
q.setProgress(int(((nrow+1)/maxRow)*100))
item = doc.getValue(doc.Offset(doc.FirstCell(selctedCell),nrow,0,1,17))
opt = []
theAnswer = -1
c = 1
for o in range(2,17,3):
if (item[o] == 1):
theAnswer = c
if (item[o+1] != ""):
opt.append(q.createOption("{}. {}".format(chr(64+c),item[o+2]),cwd+item[o+1]))
else:
opt.append(q.createOption("{}. {}".format(chr(64+c),item[o+2])))
c = c+1
if (theAnswer == -1):
raise Exception("Chose the correct answer")
if( item[1] != ""):
img = cwd+item[1]
else:
img = None
qq = q.createQuestion(title = "Soal No {}".format(nrow+1),\
description = item[0],\
indexAnswer = theAnswer, \
options = opt, itemImage=img)
q.submitQuestion(nrow,qq)
q.update()
def GoogleQuiz():
q = gquiz()
q.AttachProcessInfo(_statusBarInfoUpdate)
q.setProgress(0)
q.generateService()
q.createForm("Demo Soal")
_updateQuestion(q)
ui.SetStatusbar("creating google form quiz done!")
bas.InputBox("Open link to edit your form:","Your Google Form Quiz, done!", "{}".format(q.resultUri))
def MoodleQuiz():
q = moodleQuiz()
q.AttachProcessInfo(_statusBarInfoUpdate)
q.setProgress(0)
_updateQuestion(q)
ui.SetStatusbar("Done!")
bas.MsgBox("Check *.xml file in curent folder!")
g_exportedScripts = (MakeTemplate, GoogleQuiz, MoodleQuiz)

View File

@ -1,33 +0,0 @@
# coding: utf-8
from __future__ import unicode_literals
import sys, requests, os
from unohelper import fileUrlToSystemPath
sys.path.insert(0, "{}/{}".format(os.getcwd(),"Library"))
from gquiz import gquiz
from moodleQuiz import moodleQuiz
def test(q):
opt = [ q.createOption("A.","./asset/option1.png"),
q.createOption("B.","./asset/option2.png"),
q.createOption("C.","./asset/option3.png"),
q.createOption("D.","./asset/option4.png"),
q.createOption("E.","./asset/option5.png") ]
qq = q.createQuestion(title = "Soal No 1",\
description = "Dari gambar dibawah ini, ada bagian gambar yang hilang. Dari pilihan dibawah, manakah gambar yang benar?",\
indexAnswer = 4, options = opt, itemImage='./asset/test_image.png')
q.submitQuestion(0,qq)
q.update()
os.system("mkdir asset && mkdir secret")
os.system("cp ../../asset/* ./asset")
os.system("cp ../../secret/client_secrets.json ./secret")
q = moodleQuiz()
test(q)
q = gquiz()
q.generateService()
q.createForm("test")
test(q)

View File

@ -0,0 +1,143 @@
# coding: utf-8
from __future__ import unicode_literals
import os.path, time
from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
from pprint import pprint
import requests
from urllib.parse import urlparse
class gdoc:
def __init__(self):
'''
Args :
templateId : get the id from link GoogleForm
'''
self.image_temp_service_url = "https://tmpfiles.org/api/v1/upload"
# self.image_temp_service_url = "https://uguu.se/upload.php"
self.submition = {"requests":[]}
self.docs_service = None
self.main_docs = None
self.infoPrint = self._defaultPrint
self.progress = -1
self.resultUri = ""
self.savePath = './'
self.questionKey = []
def setProgress(self, i : int):
self.progress = i
def setSavePath(self, path):
self.savePath = path
def AttachProcessInfo(self, callback):
self.infoPrint = callback
def _defaultPrint(self, text : str, progress: int):
print("{}% {}".format(progress, text))
def generateService(self):
''' Start Tokenizing
here is the way to get token
link : https://developers.google.com/docs/api/quickstart/python
'''
SCOPES = ["https://www.googleapis.com/auth/documents",]
creds = None
# The file token.json stores the user's access and refresh tokens, and is
# created automatically when the authorization flow completes for the first
# time.
if os.path.exists('token.json'):
creds = Credentials.from_authorized_user_file('token.json', SCOPES)
self.infoPrint("token already exist",self.progress)
# If there are no (valid) credentials available, let the user log in.
if not creds or not creds.valid:
if creds and creds.expired and creds.refresh_token:
creds.refresh(Request())
self.infoPrint("refresh token",self.progress)
else:
flow = InstalledAppFlow.from_client_secrets_file(
self.savePath+'/secret/client_secret.json', SCOPES)
creds = flow.run_local_server(port=0)
self.infoPrint("generate token",self.progress)
# Save the credentials for the next run
with open('token.json', 'w') as token:
token.write(creds.to_json())
try:
self.infoPrint("creating service",self.progress)
self.docs_service = build('docs', 'v1', credentials=creds)
except HttpError as err:
print(err)
''' End Tokenizing
'''
def createDocs(self, name):
try:
self.infoPrint("creating document",self.progress)
self.main_docs = self.docs_service.documents().create(body={"title":name}).execute()
except HttpError as error:
print('An error occurred: %s' % error)
def createOption(self, value, image=None):
self.infoPrint("creating option",self.progress)
opttxt = "\t{}\r\n".format(value)
opt = [{'insertText' : {
'location':{ 'index': 1, },
'text': opttxt }}]
if(image != None):
self.infoPrint("uploading option image... ",self.progress)
req = requests.post(self.image_temp_service_url,files={"file": open(image,'rb')})
if(req.json()['status'] == 'error'):
raise Exception("upload failed : {}".format(req.json()))
time.sleep(3)
self.infoPrint("uploading option image... ok",self.progress)
u = urlparse(req.json()['data']['url'])
opt.append( { 'insertInlineImage' : {
'uri' : u._replace(path="/dl"+u.path).geturl(),
'location' : { 'index' : len(opttxt)-1}}
})
return opt
def createQuestion(self, title, description, options, indexAnswer, itemImage=None):
self.infoPrint("create question...",self.progress)
itemtxt = "{}\r\n".format(description)
item = [{'insertText' : {
'text': itemtxt,
'location':{'index': 1,}}}]
if (itemImage != None):
self.infoPrint("uploading question image...",self.progress)
req = requests.post(self.image_temp_service_url,files={"file": open(itemImage,'rb')})
if(req.json()['status'] == 'error'):
raise Exception("upload failed : {}".format(req.json()))
time.sleep(3)
self.infoPrint("uploading question image... ok",self.progress)
u = urlparse(req.json()['data']['url'])
item.append( { 'insertInlineImage' : {
'uri' : u._replace(path="/dl"+u.path).geturl(),
'location' : { 'index' : len(itemtxt)-1 }}
})
item = list(reversed(options)) + item
self.questionKey.append(indexAnswer)
return item
def submitItem(self, index, item):
self.infoPrint("submit question",self.progress)
for _item in item :
submition = {}
submition["requests"] = _item
print(submition)
r = self.docs_service.documents().batchUpdate(documentId=self.main_docs["documentId"], body=submition).execute()
print(r)
def update(self):
self.infoPrint("Updating Docs...",self.progress)
# Prints the result to show the question has been added
# get_result = self.docs_service.documents().get(documentId=self.main_docs["documentId"]).execute()
self.resultUri = self.main_docs["documentId"]
self.infoPrint("Updating Form... Done",self.progress)

View File

@ -21,11 +21,11 @@ class gquiz:
# self.image_temp_service_url = "https://uguu.se/upload.php"
self.submition = {"requests":[]}
self.form_service = None
self.drive_service = None
self.main_form = None
self.infoPrint = self._defaultPrint
self.progress = -1
self.resultUri = ""
self.savePath = './'
self.submition["requests"].append({
"updateSettings": {
@ -40,6 +40,10 @@ class gquiz:
def setProgress(self, i : int):
self.progress = i
def setSavePath(self, path):
self.savePath = path
def AttachProcessInfo(self, callback):
self.infoPrint = callback
@ -51,10 +55,7 @@ class gquiz:
here is the way to get token
link : https://developers.google.com/docs/api/quickstart/python
'''
SCOPES = ["https://www.googleapis.com/auth/forms.body",
"https://www.googleapis.com/auth/drive",
"https://www.googleapis.com/auth/drive.file",
"https://www.googleapis.com/auth/drive.appdata"]
SCOPES = ["https://www.googleapis.com/auth/forms.body",]
DISCOVERY_DOC = "https://forms.googleapis.com/$discovery/rest?version=v1"
creds = None
@ -71,7 +72,7 @@ class gquiz:
self.infoPrint("refresh token",self.progress)
else:
flow = InstalledAppFlow.from_client_secrets_file(
'./secret/client_secrets.json', SCOPES)
self.savePath+'/secret/client_secret.json', SCOPES)
creds = flow.run_local_server(port=0)
self.infoPrint("generate token",self.progress)
# Save the credentials for the next run
@ -80,10 +81,7 @@ class gquiz:
try:
self.infoPrint("creating service",self.progress)
service = build('docs', 'v1', credentials=creds)
self.form_service, self.drive_service = \
build('forms', 'v1', credentials=creds, discoveryServiceUrl=DISCOVERY_DOC, static_discovery=False),\
build('drive', 'v3', credentials=creds)
self.form_service = build('forms', 'v1', credentials=creds, discoveryServiceUrl=DISCOVERY_DOC, static_discovery=False)
except HttpError as err:
print(err)
@ -101,30 +99,6 @@ class gquiz:
except HttpError as error:
print('An error occurred: %s' % error)
def copyFile(self,origin_file_id, copy_title):
"""Copy an existing file.
Args:
service: Drive API service instance.
origin_file_id: ID of the origin file to copy.
copy_title: Title of the copy.
Returns:
The copied file if successful, None otherwise.
"""
try:
if((self.drive_service == None) or (self.form_service == None)):
raise Exception('please generate service first')
newFormId = self.drive_service.files().copy(\
fileId=origin_file_id, body={"name":copy_title})\
.execute()
print(newFormId)
self.main_form = self.form_service.forms().get(formId=newFormId["id"]).execute()
except HttpError as error:
print('An error occurred: %s' % error)
def createOption(self, value, image=None):
'''
return {"value" : "A. option 1"}
@ -205,7 +179,7 @@ class gquiz:
})
return item
def submitQuestion(self, index, item):
def submitItem(self, index, item):
""" Submit item to submition
Args:
index : location item in form

View File

@ -0,0 +1 @@
# TODO jadikan satu semua code yang berhubungan dengan autentikasi dan generate service

View File

@ -9,6 +9,10 @@ class moodleQuiz:
self.progress = -1
self.resultUri = ""
self.data = ET.Element('quiz')
self.savePath = '.'
def setSavePath(self, path):
self.savePath = path
def setProgress(self, i : int):
self.progress = i
@ -82,6 +86,6 @@ class moodleQuiz:
def update(self):
ET.indent(self.data)
print(ET.tostring(self.data))
ET.ElementTree(self.data).write("./moodleXMLMultichoiceQuestion.xml")
ET.ElementTree(self.data).write("{}/{}".format(self.savePath, "moodleXMLMultichoiceQuestion.xml"))

View File

@ -0,0 +1,64 @@
# coding: utf-8
from __future__ import unicode_literals
import sys, os
import requests
import importlib
# to run separatly from soffice
# $ soffice --calc --accept="socket,host=localhost,port=2002;urp;StarOffice.ServiceManager"
sys.path.append("/lib64/libreoffice/program/")
from scriptforge import ScriptForge, CreateScriptService
from unohelper import fileUrlToSystemPath
sys.path.insert(0, '{}/{}'.format(os.getcwd(),'Library'))
ScriptForge(hostname='localhost', port=2002)
from gquiz import gquiz
ui = CreateScriptService("UI")
doc = CreateScriptService("Calc")
bas = CreateScriptService("Basic")
q = gquiz()
q.generateService()
def get_file_id_from_link(link):
# Find the starting index of the file ID
start_index = -1
if "/d/" in link:
start_index = link.index("/d/") + 3
elif "id=" in link:
start_index = link.index("id=") + 3
elif "rs/" in link:
start_index = link.index("rs/") + 3
if start_index != -1:
# Find the ending index of the file ID
end_index = link.index("/", start_index)
if end_index == -1:
# If there is no trailing "/", use the end of the string
end_index = len(link)
# Extract the file ID
file_id = link[start_index:end_index]
return file_id
else:
# Return None if no file ID is found
return None
cells = doc.getValue("")
for col in range(0, len(cells)):
for row in range(0, len(cells[0])):
if(str(cells[col][row]).startswith("https://")):
print("found the culprit!!")
url = cells[col][row]
print(url)
Id=get_file_id_from_link(url)
file = q.drive_service.files().get(fileId=Id).execute()
newCell = "/asset/{newname}".format(newname=file["name"])
print("{new} <- {old}".format(new=newCell, old=cells[col][row]))
doc.setValue(doc.Offset("A1",col,row),newCell)

View File

@ -0,0 +1,135 @@
# coding: utf-8
from __future__ import unicode_literals
import sys, os
import requests
import importlib
# to run separatly from soffice
# $ soffice --calc --accept="socket,host=localhost,port=2002;urp;StarOffice.ServiceManager"
# uncomemnt for run separatly from soffice
# sys.path.append("/lib64/libreoffice/program/")
from scriptforge import ScriptForge, CreateScriptService
from unohelper import fileUrlToSystemPath
ui = CreateScriptService("UI")
doc = CreateScriptService("Calc")
bas = CreateScriptService("Basic")
url = fileUrlToSystemPath(XSCRIPTCONTEXT.getDocument().URL )
curpath = '/'.join([url.split('/')[x] for x in range(0,len(url.split('/'))-1)])
if not ui.Activate(url) :
bas.MsgBox("Error no window active",bas.MB_OK)
def _load_module():
#[start] comment for run embeded module
if (not 'gquiz' in sys.modules) or (not 'moodleQuiz' in sys.modules):
doc = XSCRIPTCONTEXT.getDocument()
urlem = '{}/{}'.format(url,'/Scripts/python/Library')
sys.path.insert(0, urlem)
_statusBarInfoUpdate("Load embedded modul link form {}".format(url),0)
#[end]
#[start] uncomemnt for run separatly from soffice
#sys.path.insert(0, '{}/{}'.format(os.getcwd(),'Library'))
#ScriptForge(hostname='localhost', port=2002)
#[end]
def MakeTemplate():
doc.SetArray(doc.CurrentSelection, \
(("<Text question>","<IMG question image>", \
"<isAnswerA>", "<IMG option1>", "<Text Option1>", \
"<isAnswerB>", "<IMG option2>", "<Text Option2>", \
"<isAnswerC>", "<IMG option3>", "<Text Option3>", \
"<isAnswerD>", "<IMG option4>", "<Text Option4>", \
"<isAnswerE>", "<IMG option5>", "<Text Option5>", ),))
def _statusBarInfoUpdate(text : str, progress : int):
ui.ShowProgressBar("loading...", "{}% {}".format(progress,text), progress)
def _updateQuestion(q, isReverse = False):
selctedCell = doc.CurrentSelection #
cwd = curpath
maxRow = doc.LastRow(selctedCell)+1-doc.FirstRow(selctedCell)
rnge = reversed(range(0, maxRow)) if isReverse else range(0, maxRow)
for nrow in rnge:
q.setProgress(int(((nrow+1)/maxRow)*100))
item = doc.getValue(doc.Offset(doc.FirstCell(selctedCell),nrow,0,1,17))
# item[0] <Text question>
# item[1] <IMG question image>
# item[2] <isAnswerA>
# item[3] <IMG option1>
# item[4] <Text Option1>
# item[5] <isAnswerB>
# item[6] <IMG option2>
# item[7] <Text Option2>
# item[8] <isAnswerC>
# item[9] <IMG option3>
# item[10] <Text Option3>
# item[11] <isAnswerD>
# item[12] <IMG option4>
# item[13] <Text Option4>
# item[14] <isAnswerE>
# item[15] <IMG option5>
# item[16] <Text Option5>
opt, theAnswer, c = [], -1, 1
for o in range(2, 17, 3): # mengambil kolim jawaban saja
if (item[o] == 1)
theAnswer = c
opt.append(\
q.createOption(\
"{}. {}".format(chr(64+c),item[o+2]),\
cwd+item[o+1] if (item[o+1] != "") else None))
c = c+1
if (theAnswer == -1):
raise Exception("Chose the correct answer")
img = cwd+item[1] if ( item[1] != "") else None
qq = q.createQuestion(\
title = "Soal No {}".format(nrow+1),\
description = item[0],\
indexAnswer = theAnswer, \
options = opt, itemImage=img)
q.submitItem(nrow,qq)
q.update()
def GoogleQuiz():
_load_module()
from gquiz import gquiz
q = gquiz()
q.setSavePath(curpath)
q.AttachProcessInfo(_statusBarInfoUpdate)
q.setProgress(0)
q.generateService()
q.createForm("Demo Soal") #TODO : put this mundane inside generateService()
_updateQuestion(q)
ui.SetStatusbar("creating google form quiz done!")
_statusBarInfoUpdate("Finish!!",100)
bas.InputBox("Open link to edit your form:","Your Google Form Quiz, done!", "{}".format(q.resultUri))
def GoogleDocs():
_load_module()
from gdoc import gdoc
q = gdoc()
q.setSavePath(curpath)
q.AttachProcessInfo(_statusBarInfoUpdate)
q.setProgress(0)
q.generateService()
q.createDocs("Demo Soal") #TODO : put this mundane inside generateService()
_updateQuestion(q, True)
ui.SetStatusbar("creating google form quiz done!")
_statusBarInfoUpdate("Finish!!",100)
bas.InputBox("Open link to edit your form:","Your Google Form Quiz, done!", "{}".format(q.resultUri))
def MoodleQuiz():
_load_module()
from moodleQuiz import moodleQuiz
q = moodleQuiz()
q.setSavePath(curpath)
q.AttachProcessInfo(_statusBarInfoUpdate)
q.setProgress(0)
_updateQuestion(q)
ui.SetStatusbar("Done!")
_statusBarInfoUpdate("Check *.xml file in curent folder!",100)
g_exportedScripts = (MakeTemplate, GoogleQuiz, GoogleDocs, MoodleQuiz)

View File

@ -0,0 +1,75 @@
# coding: utf-8
# run it under boring_edu_doc folder
# $ python Scripts/python/test_gquiz.py
from __future__ import unicode_literals
import os, sys, requests
if (len(sys.argv) < 2):
print("arg[1] : form, docs, moodle")
quit()
def gquiz_form_test():
'''
arg[1] = form
'''
if not 'gquiz' in sys.modules:
sys.path.insert(0, os.getcwd()+"/Scripts/python/Library/")
from gquiz import gquiz
q = gquiz()
q.setSavePath(".")
q.setProgress(0)
q.generateService()
q.setProgress(20)
q.createForm("test quiz")
q.setProgress(50)
opt = [ q.createOption("A.","./asset/option1.png"),
q.createOption("B.","./asset/option2.png"),
q.createOption("C.","./asset/option3.png"),
q.createOption("D.","./asset/option4.png"),
q.createOption("E.","./asset/option5.png") ]
q.setProgress(80)
qq = q.createQuestion(title = "Soal No 1",\
description = "Dari gambar dibawah ini, ada bagian gambar yang hilang. Dari pilihan dibawah, manakah gambar yang benar?",\
indexAnswer = 4, options = opt, itemImage='./asset/test_image.png')
q.setProgress(85)
q.submitItem(0,qq)
q.setProgress(90)
q.update()
q.setProgress(100)
print("Open link : {}".format(q.resultUri))
def gquiz_docs_test():
'''
arg[1] = docs
'''
if not 'gdoc' in sys.modules:
sys.path.insert(0, os.getcwd()+"/Scripts/python/Library/")
from gdoc import gdoc
q = gdoc()
q.setSavePath(".")
q.setProgress(0)
q.generateService()
q.setProgress(20)
q.createDocs("test quiz")
q.setProgress(50)
opt = [ q.createOption("A.","./asset/option1.png"),
q.createOption("B.","./asset/option2.png"),
q.createOption("C.","./asset/option3.png"),
q.createOption("D.","./asset/option4.png"),
q.createOption("E.","./asset/option5.png") ]
q.setProgress(80)
qq = q.createQuestion(title = "Soal No 1",\
description = "Dari gambar dibawah ini, ada bagian gambar yang hilang. Dari pilihan dibawah, manakah gambar yang benar?",\
indexAnswer = 4, options = opt, itemImage='./asset/test_image.png')
q.setProgress(85)
q.submitItem(0,qq)
q.setProgress(90)
q.update()
q.setProgress(100)
print("Open link : {}".format(q.resultUri))
if (sys.argv[1] == 'form'):
gquiz_form_test()
elif (sys.argv[1] == 'docs'):
gquiz_docs_test()

BIN
myedu.ods

Binary file not shown.

View File

@ -1 +1,12 @@
ok
Authorize credentials for a desktop application
To authenticate as an end user and access user data in your app, you need to create one or more OAuth 2.0 Client IDs. A client ID is used to identify a single app to Google's OAuth servers. If your app runs on multiple platforms, you must create a separate client ID for each platform.
In the Google Cloud console, go to Menu menu > APIs & Services > Credentials.
Go to Credentials
Click Create Credentials > OAuth client ID.
Click Application type > Desktop app.
In the Name field, type a name for the credential. This name is only shown in the Google Cloud console.
Click Create. The OAuth client created screen appears, showing your new Client ID and Client secret.
Click OK. The newly created credential appears under OAuth 2.0 Client IDs.
Save the downloaded JSON file as credentials.json, and move the file to your working directory.