def documents(config, session=False): if session is False: session = authenticate.authenticate(config) if session == False: return {"status": "error", "type": "authenticate"} cookies = { "lecmobile": "0", "ASP.NET_SessionId": session["ASP.NET_SessionId"], "LastLoginUserName": session["LastLoginUserName"], "lectiogsc": session["lectiogsc"], "LectioTicket": session["LectioTicket"] } # Insert User-agent headers and the cookie information headers = { "User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1665.2 Safari/537.36", "Content-Type": "application/x-www-form-urlencoded", "Host": "www.lectio.dk", "Origin": "https://www.lectio.dk", "Cookie": functions.implode(cookies, "{{index}}={{value}}", "; ") } url = "https://www.lectio.dk/lectio/%s/DokumentOversigt.aspx?elevid=%s&folderid=%s" % ( str(config["school_id"]), str( config["student_id"]), str(config["folder_id"])) response = proxy.session.get(url, headers=headers) html = response.text soup = Soup(html) if soup.find("table", attrs={"id": "s_m_Content_Content_DocumentGridView_ctl00" }) is None: return {"status": False, "error": "Data not found"} rows = soup.find("table", attrs={ "id": "s_m_Content_Content_DocumentGridView_ctl00" }).findAll("tr") rows.pop(0) shortDayTimeProg = re.compile( r"(?P<day_name>.*) (?P<hour>.*):(?P<minute>.*)") timeProg = re.compile( r"(?P<hour>.*):(?P<minute>.*)") # Current day, month, year dayProg = re.compile( r"(?P<day_name>.*) (?P<day>.*)/(?P<month>.*)") # Current year dateProg = re.compile(r"(?P<day>.*)/(?P<month>.*)-(?P<year>.*)") dayConversion = { u"Ma": "Mon", u"Ti": "Tue", u"On": "Wed", u"To": "Thu", u"Fr": "Fri", u"Lø": "Sat", u"Sø": "Son" } documents = [] documentIdProg = re.compile( r"\/lectio\/(?P<school_id>.*)\/dokumenthent.aspx\?documentid=(?P<document_id>.*)" ) for row in rows: elements = row.findAll("td") idGroups = documentIdProg.match(elements[1].find("a")["href"]) changer = context_card.user( { "context_card_id": elements[3]["lectiocontextcard"], "school_id": config["school_id"] }, session) if shortDayTimeProg.match(elements[4].text): timeGroups = shortDayTimeProg.match(elements[4].text) date = datetime.strptime( "%s/%s-%s %s:%s" % (dayConversion[unicode( timeGroups.group("day_name").capitalize())], today.strftime("%W"), today.strftime("%Y"), timeGroups.group("hour"), timeGroups.group("minute")), "%a/%W-%Y %H:%M") elif timeProg.match(elements[4].text): timeGroups = timeProg.match(elements[4].text) date = datetime.strptime( "%s/%s-%s %s:%s" % (today.strftime("%d"), today.strftime("%m"), today.strftime("%Y"), timeGroups.group("hour"), timeGroups.group("minute")), "%d/%m-%Y %H:%M") elif dayProg.match(elements[4].text): dayGroups = dayProg.match(elements[4].text) date = datetime.strptime( "%s/%s-%s %s:%s" % (dayGroups.group("day"), dayGroups.group("month"), today.strftime("%Y"), "12", "00"), "%d/%m-%Y %H:%M") elif dateProg.match(elements[4].text): dateGroups = dateProg.match(elements[4].text) date = datetime.strptime( "%s/%s-%s %s:%s" % (dateGroups.group("day"), dateGroups.group("month"), dateGroups.group("year"), "12", "00"), "%d/%m-%Y %H:%M") data = { "folder_id": str(config["folder_id"]), "name": unicode(elements[1].find("span")["title"].replace( "Fulde filnavn: ", "")), "extension": os.path.splitext(elements[1].find("span")["title"].replace( "Fulde filnavn: ", ""))[1].replace(".", ""), "comment": unicode(elements[2].find("span").text), "document_id": idGroups.group("document_id") if not idGroups is None else "", "size": elements[5].text.replace(",", "."), "date": date, "user": changer["user"] } documents.append(data) return {"status": "ok", "documents": documents}
def documents ( config, session = False ): if session is False: session = authenticate.authenticate(config) if session == False: return {"status" : "error", "type" : "authenticate"} cookies = { "lecmobile" : "0", "ASP.NET_SessionId" : session["ASP.NET_SessionId"], "LastLoginUserName" : session["LastLoginUserName"], "lectiogsc" : session["lectiogsc"], "LectioTicket" : session["LectioTicket"] } # Insert User-agent headers and the cookie information headers = { "User-Agent" : "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1665.2 Safari/537.36", "Content-Type" : "application/x-www-form-urlencoded", "Host" : "www.lectio.dk", "Origin" : "https://www.lectio.dk", "Cookie" : functions.implode(cookies, "{{index}}={{value}}", "; ") } url = "https://www.lectio.dk/lectio/%s/DokumentOversigt.aspx?elevid=%s&folderid=%s" %( str(config["school_id"]), str(config["student_id"]), str(config["folder_id"]) ) response = proxy.session.get(url, headers=headers) html = response.text soup = Soup(html) if soup.find("table", attrs={"id" : "s_m_Content_Content_DocumentGridView_ctl00"}) is None: return { "status" : False, "error" : "Data not found" } rows = soup.find("table", attrs={"id" : "s_m_Content_Content_DocumentGridView_ctl00"}).findAll("tr") rows.pop(0) shortDayTimeProg = re.compile(r"(?P<day_name>.*) (?P<hour>.*):(?P<minute>.*)") timeProg = re.compile(r"(?P<hour>.*):(?P<minute>.*)") # Current day, month, year dayProg = re.compile(r"(?P<day_name>.*) (?P<day>.*)/(?P<month>.*)") # Current year dateProg = re.compile(r"(?P<day>.*)/(?P<month>.*)-(?P<year>.*)") dayConversion = { u"Ma" : "Mon", u"Ti" : "Tue", u"On" : "Wed", u"To" : "Thu", u"Fr" : "Fri", u"Lø" : "Sat", u"Sø" : "Son" } documents = [] documentIdProg = re.compile(r"\/lectio\/(?P<school_id>.*)\/dokumenthent.aspx\?documentid=(?P<document_id>.*)") for row in rows: elements = row.findAll("td") idGroups = documentIdProg.match(elements[1].find("a")["href"]) changer = context_card.user({ "context_card_id" : elements[3]["lectiocontextcard"], "school_id" : config["school_id"] }, session) if shortDayTimeProg.match(elements[4].text): timeGroups = shortDayTimeProg.match(elements[4].text) date = datetime.strptime("%s/%s-%s %s:%s" % (dayConversion[unicode(timeGroups.group("day_name").capitalize())], today.strftime("%W"), today.strftime("%Y"), timeGroups.group("hour"), timeGroups.group("minute")), "%a/%W-%Y %H:%M") elif timeProg.match(elements[4].text): timeGroups = timeProg.match(elements[4].text) date = datetime.strptime("%s/%s-%s %s:%s" % (today.strftime("%d"), today.strftime("%m"), today.strftime("%Y"), timeGroups.group("hour"), timeGroups.group("minute")), "%d/%m-%Y %H:%M") elif dayProg.match(elements[4].text): dayGroups = dayProg.match(elements[4].text) date = datetime.strptime("%s/%s-%s %s:%s" % (dayGroups.group("day"), dayGroups.group("month"), today.strftime("%Y"), "12", "00"), "%d/%m-%Y %H:%M") elif dateProg.match(elements[4].text): dateGroups = dateProg.match(elements[4].text) date = datetime.strptime("%s/%s-%s %s:%s" % (dateGroups.group("day"), dateGroups.group("month"), dateGroups.group("year"), "12", "00"), "%d/%m-%Y %H:%M") data = { "folder_id" : str(config["folder_id"]), "name" : unicode(elements[1].find("span")["title"].replace("Fulde filnavn: ", "")), "extension" : os.path.splitext(elements[1].find("span")["title"].replace("Fulde filnavn: ", ""))[1].replace(".", ""), "comment" : unicode(elements[2].find("span").text), "document_id" : idGroups.group("document_id") if not idGroups is None else "", "size" : elements[5].text.replace(",", "."), "date" : date, "user" : changer["user"] } documents.append(data) return { "status" : "ok", "documents" : documents }
def document(config, session=False): url = "https://www.lectio.dk/lectio/%s/dokumentrediger.aspx?dokumentid=%s" % ( str(config["school_id"]), str(config["document_id"])) if session is False: session = authenticate.authenticate(config) if session == False: return {"status": "error", "type": "authenticate"} cookies = { "lecmobile": "0", "ASP.NET_SessionId": session["ASP.NET_SessionId"], "LastLoginUserName": session["LastLoginUserName"], "lectiogsc": session["lectiogsc"], "LectioTicket": session["LectioTicket"] } # Insert User-agent headers and the cookie information headers = { "User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1665.2 Safari/537.36", "Content-Type": "application/x-www-form-urlencoded", "Host": "www.lectio.dk", "Origin": "https://www.lectio.dk", "Cookie": functions.implode(cookies, "{{index}}={{value}}", "; ") } response = proxy.session.get(url, headers=headers) html = response.text soup = Soup(html) if soup.find("div", attrs={"id": "m_Content_Dokument_pa"}) is None: return {"status": False, "error": "Data not found"} offset = 0 elements = soup.find("div", attrs={ "id": "m_Content_Dokument_pa" }).findAll("td") if len(elements) < 7: offset = 1 creator = context_card.user( { "context_card_id": elements[3 - offset].find("span")["lectiocontextcard"], "school_id": config["school_id"] }, session)["user"] changer = elements[4 - offset].find("span")["lectiocontextcard"] elements[4 - offset].find("span").decompose() dateText = elements[4 - offset].text.replace(" af ", "").strip() dateTimeProg = re.compile( r"(?P<day>.*)/(?P<month>.*)-(?P<year>.*) (?P<hour>.*):(?P<minute>.*)") dateGroups = dateTimeProg.match(dateText) date = datetime.strptime( "%s/%s-%s %s:%s" % (functions.zeroPadding(dateGroups.group("day")), functions.zeroPadding(dateGroups.group("month")), dateGroups.group("year"), dateGroups.group("hour"), dateGroups.group("minute")), "%d/%m-%Y %H:%M") if not dateGroups is None else "" connectionRows = soup.find("table", attrs={ "id": "m_Content_AffiliationsGV" }).findAll("tr") connectionRows.pop(0) connections = [] for row in connectionRows: rowElements = row.findAll("td") data = { "context_card_id": rowElements[0]["lectiocontextcard"], "type": "team" if "H" in rowElements[0]["lectiocontextcard"] else "teacher" if "T" in rowElements[0]["lectiocontextcard"] else "student", "name": unicode(rowElements[0].find("span").text), "can_edit": True if "checked" in rowElements[1].find("input").attrs else False } if rowElements[2].find("select"): folder_id = rowElements[2].find("select").select( 'option[selected="selected"]')[0]["value"] data["folder_id"] = folder_id connections.append(data) document = { "name": unicode(elements[0].find("a").text).replace("\t", "").replace( "\n", "").replace("\r", "").strip(), "extension": os.path.splitext(elements[0].find("a").text.replace("\t", "").replace( "\n", "").replace("\r", "").strip())[1].replace(".", ""), "size": elements[2 - offset].text.replace(",", ".").replace("\t", "").replace( "\n", "").replace("\r", "").strip(), "document_id": str(config["document_id"]), "creator": creator, "changer": { "context_card_id": changer, "type": "teacher" if "T" in changer else "student", "date": date }, "comment": soup.find("textarea", attrs={ "id": "m_Content_EditDocComments_tb" }).text.replace("\r\n", ""), "public": True if "checked" in soup.find("input", attrs={ "id": "m_Content_EditDocIsPublic" }).attrs else False, "connections": connections, "term": { "value": soup.find("select", attrs={ "id": "m_ChooseTerm_term" }).select('option[selected="selected"]')[0]["value"], "years_string": soup.find("select", attrs={ "id": "m_ChooseTerm_term" }).select('option[selected="selected"]')[0].text } } return {"status": "ok", "document": document}
def message(config, session=False): url = "https://www.lectio.dk/lectio/%s/beskeder2.aspx?type=liste&elevid=%s" % ( str(config["school_id"]), str(config["student_id"])) if session is False: session = authenticate.authenticate(config) if session == False: return {"status": "error", "type": "authenticate"} # Insert the session information from the auth function cookies = { "lecmobile": "0", "ASP.NET_SessionId": session["ASP.NET_SessionId"], "LastLoginUserName": session["LastLoginUserName"], "lectiogsc": session["lectiogsc"], "LectioTicket": session["LectioTicket"] } # Insert User-agent headers and the cookie information headers = { "User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1665.2 Safari/537.36", "Content-Type": "application/x-www-form-urlencoded", "Host": "www.lectio.dk", "Origin": "https://www.lectio.dk", "Cookie": functions.implode(cookies, "{{index}}={{value}}", "; ") } response = proxy.session.get(url, headers=headers) html = response.text soup = Soup(html) viewStateX = soup.find("input", attrs={"id": "__VIEWSTATEX"})["value"] settings = { "__EVENTTARGET": "__Page", "__EVENTARGUMENT": "$LB2$_MC_$_%s" % (str(config["thread_id"])), "__VIEWSTATEX": viewStateX, } response = proxy.session.post(url, data=settings, headers=headers) html = response.text soup = Soup(html) if soup.find("div", attrs={"id": "s_m_Content_Content_ViewThreadPagePanel" }) is None: return {"status": False, "error": "Data not found"} flagged = False if soup.find( "input", attrs={"id": "s_m_Content_Content_FlagThisThreadBox" })["src"] == "/lectio/img/flagoff.gif" else True originalElements = soup.find("table", attrs={ "class": "ShowMessageRecipients" }).findAll("td") originalSenderUser = context_card.user( { "context_card_id": originalElements[8].find("span")["lectiocontextcard"], "school_id": config["school_id"] }, session) originalSenderUser["user"]["user_context_card_id"] = originalElements[ 8].find("span")["lectiocontextcard"] originalSenderUser["user"]["person_id"] = originalElements[8].find( "span")["lectiocontextcard"].replace("U", "") originalSubject = unicode(functions.cleanText(originalElements[2].text)) recipients = [] studentRecipientProg = re.compile( r"(?P<name>.*) \((?P<student_class_id>.*)\)") teacherRecipientProg = re.compile(r"(?P<name>.*) \((?P<abbrevation>.*)\)") # Fill in the single users, added as recipients for row in originalElements[11].findAll("span"): context_card_id = row["lectiocontextcard"] userType = "" data = {"context_card_id": context_card_id} if "S" in context_card_id: userType = "student" studentGroups = studentRecipientProg.match(row.text) data["person_id"] = context_card_id.replace("S", "") data["student_id"] = context_card_id.replace("S", "") data["name"] = unicode(studentGroups.group( "name")) if not studentGroups is None else "" data["student_class_id"] = studentGroups.group( "student_class_id") if not studentGroups is None else "" elif "T" in context_card_id: userType = "teacher" teacherGroups = teacherRecipientProg.match(row.text) data["person_id"] = context_card_id.replace("T", "") data["teacher_id"] = context_card_id.replace("T", "") data["abbrevation"] = unicode(teacherGroups.group( "abbrevation")) if not teacherGroups is None else "" data["name"] = unicode(teacherGroups.group( "name")) if not teacherGroups is None else "" data["type"] = userType recipients.append(data) row.decompose() recipientRows = originalElements[11].text.split(", ") for row in recipientRows: text = row.replace("\n", "").replace("\r", "").replace("\t", "") if "Holdet" in text: text = text.replace("Holdet ", "") recipients.append({"type": "team", "name": unicode(text)}) elif "Gruppen" in text: text = text.replace("Gruppen ", "") recipients.append({"type": "group", "name": unicode(text)}) messages = [] answerProg = re.compile( r"javascript:__doPostBack\('__Page','ANSWERMESSAGE_(?P<message_id>.*)'\);" ) dateTimeProg = re.compile( r"(?P<day>.*)\/(?P<month>.*)-(?P<year>.*) (?P<hour>.*):(?P<minute>.*)") messageLevels = {} for row in soup.find("table", attrs={ "id": "s_m_Content_Content_ThreadTable" }).findAll("tr"): if not row.find("table") is None: level = row.findAll(has_colspan)[0]["colspan"] data = {} messageDetailElements = row.find("table").findAll("td") # Subject data["subject"] = unicode(messageDetailElements[0].find("h4").text) messageDetailElements[0].find("h4").decompose() # Sender messageSender = context_card.user( { "context_card_id": messageDetailElements[0].find("span")["lectiocontextcard"], "school_id": config["school_id"] }, session) messageSender["user"]["user_context_card_id"] = originalElements[ 8].find("span")["lectiocontextcard"] messageSender["user"]["person_id"] = originalElements[8].find( "span")["lectiocontextcard"].replace("U", "") data["sender"] = messageSender["user"] messageDetailElements[0].find("span").decompose() # Time timeText = messageDetailElements[0].text.replace( "Af , ", "").strip().replace("\n", "").replace("\t", "") dateGroups = dateTimeProg.match(timeText) data["date"] = datetime.strptime( "%s/%s-%s %s:%s" % (functions.zeroPadding(dateGroups.group("day")), functions.zeroPadding(dateGroups.group("month")), dateGroups.group("year"), dateGroups.group("hour"), dateGroups.group("minute")), "%d/%m-%Y %H:%M") if not dateGroups is None else "" # Message id answerGroups = answerProg.match( messageDetailElements[1].find("button")["onclick"]) message_id = answerGroups.group( "message_id") if not answerGroups is None else "" data["message_id"] = message_id row.find("table").decompose() # Get message text data["message"] = unicode(row.text.strip()) # Get parent if str(int(level) + 1) in messageLevels: data["parrent_id"] = messageLevels[str(int(level) + 1)] messageLevels[level] = message_id messages.append(data) messageInfo = { "original_subject": originalSubject, "flagged": flagged, "original_sender": originalSenderUser["user"], "recipients": recipients, "messages": messages } return { "status": "ok", "message": messageInfo, }
def document ( config, session = False ): url = "https://www.lectio.dk/lectio/%s/dokumentrediger.aspx?dokumentid=%s" % ( str(config["school_id"]), str(config["document_id"]) ) if session is False: session = authenticate.authenticate(config) if session == False: return {"status" : "error", "type" : "authenticate"} cookies = { "lecmobile" : "0", "ASP.NET_SessionId" : session["ASP.NET_SessionId"], "LastLoginUserName" : session["LastLoginUserName"], "lectiogsc" : session["lectiogsc"], "LectioTicket" : session["LectioTicket"] } # Insert User-agent headers and the cookie information headers = { "User-Agent" : "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1665.2 Safari/537.36", "Content-Type" : "application/x-www-form-urlencoded", "Host" : "www.lectio.dk", "Origin" : "https://www.lectio.dk", "Cookie" : functions.implode(cookies, "{{index}}={{value}}", "; ") } response = proxy.session.get(url, headers=headers) html = response.text soup = Soup(html) if soup.find("div", attrs={"id" : "m_Content_Dokument_pa"}) is None: return { "status" : False, "error" : "Data not found" } offset = 0 elements = soup.find("div", attrs={"id" : "m_Content_Dokument_pa"}).findAll("td") if len(elements) < 7: offset = 1 creator = context_card.user({ "context_card_id" : elements[3-offset].find("span")["lectiocontextcard"], "school_id" : config["school_id"] }, session)["user"] changer = elements[4-offset].find("span")["lectiocontextcard"] elements[4-offset].find("span").decompose() dateText = elements[4-offset].text.replace(" af ", "").strip() dateTimeProg = re.compile(r"(?P<day>.*)/(?P<month>.*)-(?P<year>.*) (?P<hour>.*):(?P<minute>.*)") dateGroups = dateTimeProg.match(dateText) date = datetime.strptime("%s/%s-%s %s:%s" % (functions.zeroPadding(dateGroups.group("day")), functions.zeroPadding(dateGroups.group("month")), dateGroups.group("year"), dateGroups.group("hour"), dateGroups.group("minute")), "%d/%m-%Y %H:%M") if not dateGroups is None else "" connectionRows = soup.find("table", attrs={"id" : "m_Content_AffiliationsGV"}).findAll("tr") connectionRows.pop(0) connections = [] for row in connectionRows: rowElements = row.findAll("td") data = { "context_card_id" : rowElements[0]["lectiocontextcard"], "type" : "team" if "H" in rowElements[0]["lectiocontextcard"] else "teacher" if "T" in rowElements[0]["lectiocontextcard"] else "student", "name" : unicode(rowElements[0].find("span").text), "can_edit" : True if "checked" in rowElements[1].find("input").attrs else False } if rowElements[2].find("select"): folder_id = rowElements[2].find("select").select('option[selected="selected"]')[0]["value"] data["folder_id"] = folder_id connections.append(data) document = { "name" : unicode(elements[0].find("a").text).replace("\t", "").replace("\n", "").replace("\r", "").strip(), "extension" : os.path.splitext(elements[0].find("a").text.replace("\t", "").replace("\n", "").replace("\r", "").strip())[1].replace(".", ""), "size" : elements[2-offset].text.replace(",", ".").replace("\t", "").replace("\n", "").replace("\r", "").strip(), "document_id" : str(config["document_id"]), "creator" : creator, "changer" : { "context_card_id" : changer, "type" : "teacher" if "T" in changer else "student", "date" : date }, "comment" : soup.find("textarea", attrs={"id" : "m_Content_EditDocComments_tb"}).text.replace("\r\n",""), "public" : True if "checked" in soup.find("input", attrs={"id" : "m_Content_EditDocIsPublic"}).attrs else False, "connections" : connections, "term" : { "value" : soup.find("select", attrs={"id" : "m_ChooseTerm_term"}).select('option[selected="selected"]')[0]["value"], "years_string" : soup.find("select", attrs={"id" : "m_ChooseTerm_term"}).select('option[selected="selected"]')[0].text } } return { "status" : "ok", "document" : document }
def survey_report ( config, session = False ): url = "https://www.lectio.dk/lectio/%s/spoergeskema/spoergeskemarapportering.aspx?id=%s" % ( str(config["school_id"]), str(config["survey_id"]) ) if session is False: session = authenticate.authenticate(config) if session == False: return {"status" : "error", "type" : "authenticate"} # Insert the session information from the auth function cookies = { "lecmobile" : "0", "ASP.NET_SessionId" : session["ASP.NET_SessionId"], "LastLoginUserName" : session["LastLoginUserName"], "lectiogsc" : session["lectiogsc"], "LectioTicket" : session["LectioTicket"] } # Insert User-agent headers and the cookie information headers = { "User-Agent" : "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1665.2 Safari/537.36", "Content-Type" : "application/x-www-form-urlencoded", "Host" : "www.lectio.dk", "Origin" : "https://www.lectio.dk", "Cookie" : functions.implode(cookies, "{{index}}={{value}}", "; ") } response = proxy.session.get(url, headers=headers) html = response.text soup = Soup(html) if soup.find("div", attrs={"id" : "m_Content_sdasd_pa"}) is None: return { "status" : False, "error" : "Data not found" } dateTimeProg = re.compile(r"(?P<day>.*)/(?P<month>.*)-(?P<year>.*) (?P<hour>.*):(?P<minute>.*)") informationTables = soup.find("div", attrs={"id" : "m_Content_sdasd_pa"}).findAll("table") infoElements = informationTables[0].findAll("td") dateGroups = dateTimeProg.match(infoElements[2].text) answerDate = datetime.strptime("%s/%s-%s %s:%s" % (functions.zeroPadding(dateGroups.group("day")), functions.zeroPadding(dateGroups.group("month")), dateGroups.group("year"), dateGroups.group("hour"), dateGroups.group("minute")), "%d/%m-%Y %H:%M") if not dateGroups is None else "" owner = context_card.user({ "context_card_id" : infoElements[1].find("span")["lectiocontextcard"], "school_id" : str(config["school_id"]) }, session)["user"] ownerUser = { "context_cards" : [infoElements[1].find("span")["lectiocontextcard"], owner["context_card_id"]], "picture_id" : owner["picture_id"], "name" : owner["name"], "type" : owner["type"] } if owner["type"] == "student": ownerUser["student_id"] = owner["student_id"] else: ownerUser["teacher_id"] = owner["teacher_id"] information = { "title" : infoElements[0].text.encode("utf8"), "answer_date" : answerDate, "owner" : ownerUser } statElements = informationTables[1].findAll("td") stats = { "teachers" : { "registred" : statElements[1].text, "submitted" : statElements[2].text, "submitted_with_unsubscribed" : statElements[3].text, "not_submitted" : statElements[4].text }, "students" : { "registred" : statElements[5].text, "submitted" : statElements[6].text, "submitted_with_unsubscribed" : statElements[7].text, "not_submitted" : statElements[8].text }, "total" : { "registred" : statElements[9].text, "submitted" : statElements[10].text, "submitted_with_unsubscribed" : statElements[11].text, "not_submitted" : statElements[12].text } } sections = [] section_number = None section_title = None section_elements = [] section_description = None current_question_title = None current_question_number = None current_question_description = None titleProg = re.compile(r"(?P<number>[\d\.\d\S]*) (?P<title>.*)") type = "text" answerStats = [] unanswered = 0 unansweredPercent = 0 for row in soup.find(attrs={"id" : "m_Content_ctl00_pa"}).find("table").findAll("tr", recursive=False): elements = row.findAll("td") text = elements[0].text.strip().replace("\r", "").replace("\t", "") if len(text) > 0: if not elements[0].find("h3") is None: titleGroups = titleProg.match(elements[0].find("h3").text) if not "." in titleGroups.group("number"): if not section_number is None: sections.append({ "number" : section_number, "title" : section_title, "elements" : section_elements, "description" : section_description }) section_number = None section_title = None section_elements = [] section_description = None section_number = titleGroups.group("number") if not titleGroups is None else None section_title = titleGroups.group("title") if not titleGroups is None else None elements[0].find("h3").decompose() section_description = elements[0].text.replace("\r\n", "").replace("\t", "").strip().strip("\n") else: current_question_number = titleGroups.group("number") if not titleGroups is None else None current_question_title = titleGroups.group("title") if not titleGroups is None else None elements[0].find("h3").decompose() current_question_description = elements[0].text.replace("\r\n", "").replace("\t", "").strip().strip("\n") else: tables = row.findAll("table") answers = [] if tables[0].find("img") is None: for x in tables[0].findAll("tr"): xElements = x.findAll("td") if type == "checkbox": options = xElements[3].text.split(", ") else: options = [xElements[3].text] if xElements[2].text == "anonym": answers.append({ "anonymous" : True, "respondent_id" : xElements[0].text, "options" : options }) else: answers.append({ "anonymous" : False, "options" : options, "user_context_card_id" : xElements[0].find("span")["lectiocontextcard"], "user_text_id" : xElements[1].text, "user_team_text" : xElements[2].text }) section_elements.append({ "number" : current_question_number.encode("utf8"), "title" : current_question_title.encode("utf8"), "description" : current_question_description.encode("utf8"), "type" : type, "answers" : answers, "answer_stats" : answerStats, "unanswered" : str(unanswered), "unanswered_percent" : str(unansweredPercent) }) type = "text" answerStats = [] unanswered = 0 unansweredPercent = 0 else: for x in tables[0].findAll("tr"): xElements = x.findAll("td") if x.find("th").text == "Ubesvaret": type = "radio" unanswered = xElements[1].text unansweredPercent = xElements[2].text.replace(" %", "") else: type = "checkbox" answerStats.append({ "text" : x.find("th").text.encode("utf8"), "number" : xElements[1].text, "percent" : xElements[2].text.replace(" %", "").replace(",", ".") }) if section_number == None: section_number = 1 section_title = "" section_description = "" sections.append({ "number" : section_number, "title" : section_title, "elements" : section_elements, "description" : section_description }) return { "status" : "ok", "information" : information, "stats" : stats, "sections" : sections }
def survey_answer_page ( config, session = False ): url = "https://www.lectio.dk/lectio/%s/spoergeskema_besvar.aspx?id=%s" % ( str(config["school_id"]), str(config["survey_id"]) ) if session is False: session = authenticate.authenticate(config) if session == False: return {"status" : "error", "type" : "authenticate"} # Insert the session information from the auth function cookies = { "lecmobile" : "0", "ASP.NET_SessionId" : session["ASP.NET_SessionId"], "LastLoginUserName" : session["LastLoginUserName"], "lectiogsc" : session["lectiogsc"], "LectioTicket" : session["LectioTicket"] } # Insert User-agent headers and the cookie information headers = { "User-Agent" : "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1665.2 Safari/537.36", "Content-Type" : "application/x-www-form-urlencoded", "Host" : "www.lectio.dk", "Origin" : "https://www.lectio.dk", "Cookie" : functions.implode(cookies, "{{index}}={{value}}", "; ") } response = proxy.session.get(url, headers=headers) html = response.text soup = Soup(html) if soup.find("table", attrs={"id" : "m_Content_InfoTable"}) is None: return { "status" : False, "error" : "Data not found" } elements = soup.find("table", attrs={"id" : "m_Content_InfoTable"}).findAll("td") owner = context_card.user({ "context_card_id" : elements[1].find("span")["lectiocontextcard"], "school_id" : str(config["school_id"]) }, session)["user"] ownerUser = { "context_cards" : [elements[1].find("span")["lectiocontextcard"], owner["context_card_id"]], "picture_id" : owner["picture_id"], "name" : owner["name"], "type" : owner["type"] } if owner["type"] == "student": ownerUser["student_id"] = owner["student_id"] else: ownerUser["teacher_id"] = owner["teacher_id"] information = { "title" : elements[0].text.encode("utf8"), "owner" : ownerUser, "anonymous" : True if elements[2].text == "Ja" else False, "teachers" : elements[3].text.split(", "), "teams" : elements[4].text.split(", ") } sections = [] section_number = None section_title = None section_elements = [] section_description = None titleProg = re.compile(r"(?P<number>[\d]*) (?P<title>.*)") subTitleProg = re.compile(r"(?P<number>[\d\.\d\S]*) (?P<title>.*)") for row in soup.find(attrs={"id" : "m_Content_questionIsland2_pa"}).findAll("table"): if row.find("h3") is None: if not row.find(attrs={"type" : "RADIO"}) is None: type = "radio" elif not row.find(attrs={"type" : "CHECKBOX"}) is None: type = "checkbox" else: type = "text" lines = row.find("h4").text.replace("\t", "").replace("\r", "").strip().split("\n") titleGroups = subTitleProg.match(str(lines[0]) + " " + str(lines[1])) options = [] section_id = None if type == "text": section_id = row.find("textarea")["name"].replace("answer_", "") options.append({ "type" : "text", "name" : row.find("textarea")["name"] }) else: for element in row.findAll("div"): section_id = element.find("input")["name"].replace("answer_", "") options.append({ "title" : element.find("label").text.encode("utf8"), "value" : element.find("input")["value"], "name" : element.find("input")["name"], "type" : type }) section_elements.append({ "type" : type, "title" : titleGroups.group("title") if not titleGroups is None else "", "description" : row.find(attrs={"class" : "discreteCell"}).text.replace("\r", "").replace("\n", "").replace("\t", "").strip(), "number" : titleGroups.group("number") if not titleGroups is None else "", "options" : options, "section_id" : section_id }) else: if not section_number is None: sections.append({ "number" : section_number, "title" : section_title, "elements" : section_elements, "description" : section_description }) section_number = None section_title = None section_elements = [] section_description = None lines = row.find("h3").text.replace("\t", "").replace("\r", "").strip().split("\n") titleGroups = titleProg.match(str(lines[0]) + " " + str(lines[1])) section_number = titleGroups.group("number") if not titleGroups is None else None section_title = titleGroups.group("title") if not titleGroups is None else None section_description = row.find(attrs={"class" : "discreteCell"}).text.replace("\r\n", "").replace("\t", "").strip() if section_number == None: section_number = 1 section_title = "" section_description = "" sections.append({ "number" : section_number, "title" : section_title, "elements" : section_elements, "description" : section_description }) return { "status" : "ok", "information" : information, "sections" : sections }
def survey_report(config, session=False): url = "https://www.lectio.dk/lectio/%s/spoergeskema/spoergeskemarapportering.aspx?id=%s" % ( str(config["school_id"]), str(config["survey_id"])) if session is False: session = authenticate.authenticate(config) if session == False: return {"status": "error", "type": "authenticate"} # Insert the session information from the auth function cookies = { "lecmobile": "0", "ASP.NET_SessionId": session["ASP.NET_SessionId"], "LastLoginUserName": session["LastLoginUserName"], "lectiogsc": session["lectiogsc"], "LectioTicket": session["LectioTicket"] } # Insert User-agent headers and the cookie information headers = { "User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1665.2 Safari/537.36", "Content-Type": "application/x-www-form-urlencoded", "Host": "www.lectio.dk", "Origin": "https://www.lectio.dk", "Cookie": functions.implode(cookies, "{{index}}={{value}}", "; ") } response = proxy.session.get(url, headers=headers) html = response.text soup = Soup(html) if soup.find("div", attrs={"id": "m_Content_sdasd_pa"}) is None: return {"status": False, "error": "Data not found"} dateTimeProg = re.compile( r"(?P<day>.*)/(?P<month>.*)-(?P<year>.*) (?P<hour>.*):(?P<minute>.*)") informationTables = soup.find("div", attrs={ "id": "m_Content_sdasd_pa" }).findAll("table") infoElements = informationTables[0].findAll("td") dateGroups = dateTimeProg.match(infoElements[2].text) answerDate = datetime.strptime( "%s/%s-%s %s:%s" % (functions.zeroPadding(dateGroups.group("day")), functions.zeroPadding(dateGroups.group("month")), dateGroups.group("year"), dateGroups.group("hour"), dateGroups.group("minute")), "%d/%m-%Y %H:%M") if not dateGroups is None else "" owner = context_card.user( { "context_card_id": infoElements[1].find("span")["lectiocontextcard"], "school_id": str(config["school_id"]) }, session)["user"] ownerUser = { "context_cards": [ infoElements[1].find("span")["lectiocontextcard"], owner["context_card_id"] ], "picture_id": owner["picture_id"], "name": owner["name"], "type": owner["type"] } if owner["type"] == "student": ownerUser["student_id"] = owner["student_id"] else: ownerUser["teacher_id"] = owner["teacher_id"] information = { "title": infoElements[0].text.encode("utf8"), "answer_date": answerDate, "owner": ownerUser } statElements = informationTables[1].findAll("td") stats = { "teachers": { "registred": statElements[1].text, "submitted": statElements[2].text, "submitted_with_unsubscribed": statElements[3].text, "not_submitted": statElements[4].text }, "students": { "registred": statElements[5].text, "submitted": statElements[6].text, "submitted_with_unsubscribed": statElements[7].text, "not_submitted": statElements[8].text }, "total": { "registred": statElements[9].text, "submitted": statElements[10].text, "submitted_with_unsubscribed": statElements[11].text, "not_submitted": statElements[12].text } } sections = [] section_number = None section_title = None section_elements = [] section_description = None current_question_title = None current_question_number = None current_question_description = None titleProg = re.compile(r"(?P<number>[\d\.\d\S]*) (?P<title>.*)") type = "text" answerStats = [] unanswered = 0 unansweredPercent = 0 for row in soup.find(attrs={ "id": "m_Content_ctl00_pa" }).find("table").findAll("tr", recursive=False): elements = row.findAll("td") text = elements[0].text.strip().replace("\r", "").replace("\t", "") if len(text) > 0: if not elements[0].find("h3") is None: titleGroups = titleProg.match(elements[0].find("h3").text) if not "." in titleGroups.group("number"): if not section_number is None: sections.append({ "number": section_number, "title": section_title, "elements": section_elements, "description": section_description }) section_number = None section_title = None section_elements = [] section_description = None section_number = titleGroups.group( "number") if not titleGroups is None else None section_title = titleGroups.group( "title") if not titleGroups is None else None elements[0].find("h3").decompose() section_description = elements[0].text.replace( "\r\n", "").replace("\t", "").strip().strip("\n") else: current_question_number = titleGroups.group( "number") if not titleGroups is None else None current_question_title = titleGroups.group( "title") if not titleGroups is None else None elements[0].find("h3").decompose() current_question_description = elements[0].text.replace( "\r\n", "").replace("\t", "").strip().strip("\n") else: tables = row.findAll("table") answers = [] if tables[0].find("img") is None: for x in tables[0].findAll("tr"): xElements = x.findAll("td") if type == "checkbox": options = xElements[3].text.split(", ") else: options = [xElements[3].text] if xElements[2].text == "anonym": answers.append({ "anonymous": True, "respondent_id": xElements[0].text, "options": options }) else: answers.append({ "anonymous": False, "options": options, "user_context_card_id": xElements[0].find("span")["lectiocontextcard"], "user_text_id": xElements[1].text, "user_team_text": xElements[2].text }) section_elements.append({ "number": current_question_number.encode("utf8"), "title": current_question_title.encode("utf8"), "description": current_question_description.encode("utf8"), "type": type, "answers": answers, "answer_stats": answerStats, "unanswered": str(unanswered), "unanswered_percent": str(unansweredPercent) }) type = "text" answerStats = [] unanswered = 0 unansweredPercent = 0 else: for x in tables[0].findAll("tr"): xElements = x.findAll("td") if x.find("th").text == "Ubesvaret": type = "radio" unanswered = xElements[1].text unansweredPercent = xElements[2].text.replace( " %", "") else: type = "checkbox" answerStats.append({ "text": x.find("th").text.encode("utf8"), "number": xElements[1].text, "percent": xElements[2].text.replace(" %", "").replace( ",", ".") }) if section_number == None: section_number = 1 section_title = "" section_description = "" sections.append({ "number": section_number, "title": section_title, "elements": section_elements, "description": section_description }) return { "status": "ok", "information": information, "stats": stats, "sections": sections }
def survey_answer_page(config, session=False): url = "https://www.lectio.dk/lectio/%s/spoergeskema_besvar.aspx?id=%s" % ( str(config["school_id"]), str(config["survey_id"])) if session is False: session = authenticate.authenticate(config) if session == False: return {"status": "error", "type": "authenticate"} # Insert the session information from the auth function cookies = { "lecmobile": "0", "ASP.NET_SessionId": session["ASP.NET_SessionId"], "LastLoginUserName": session["LastLoginUserName"], "lectiogsc": session["lectiogsc"], "LectioTicket": session["LectioTicket"] } # Insert User-agent headers and the cookie information headers = { "User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1665.2 Safari/537.36", "Content-Type": "application/x-www-form-urlencoded", "Host": "www.lectio.dk", "Origin": "https://www.lectio.dk", "Cookie": functions.implode(cookies, "{{index}}={{value}}", "; ") } response = proxy.session.get(url, headers=headers) html = response.text soup = Soup(html) if soup.find("table", attrs={"id": "m_Content_InfoTable"}) is None: return {"status": False, "error": "Data not found"} elements = soup.find("table", attrs={ "id": "m_Content_InfoTable" }).findAll("td") owner = context_card.user( { "context_card_id": elements[1].find("span")["lectiocontextcard"], "school_id": str(config["school_id"]) }, session)["user"] ownerUser = { "context_cards": [ elements[1].find("span")["lectiocontextcard"], owner["context_card_id"] ], "picture_id": owner["picture_id"], "name": owner["name"], "type": owner["type"] } if owner["type"] == "student": ownerUser["student_id"] = owner["student_id"] else: ownerUser["teacher_id"] = owner["teacher_id"] information = { "title": elements[0].text.encode("utf8"), "owner": ownerUser, "anonymous": True if elements[2].text == "Ja" else False, "teachers": elements[3].text.split(", "), "teams": elements[4].text.split(", ") } sections = [] section_number = None section_title = None section_elements = [] section_description = None titleProg = re.compile(r"(?P<number>[\d]*) (?P<title>.*)") subTitleProg = re.compile(r"(?P<number>[\d\.\d\S]*) (?P<title>.*)") for row in soup.find(attrs={ "id": "m_Content_questionIsland2_pa" }).findAll("table"): if row.find("h3") is None: if not row.find(attrs={"type": "RADIO"}) is None: type = "radio" elif not row.find(attrs={"type": "CHECKBOX"}) is None: type = "checkbox" else: type = "text" lines = row.find("h4").text.replace("\t", "").replace( "\r", "").strip().split("\n") titleGroups = subTitleProg.match( str(lines[0]) + " " + str(lines[1])) options = [] section_id = None if type == "text": section_id = row.find("textarea")["name"].replace( "answer_", "") options.append({ "type": "text", "name": row.find("textarea")["name"] }) else: for element in row.findAll("div"): section_id = element.find("input")["name"].replace( "answer_", "") options.append({ "title": element.find("label").text.encode("utf8"), "value": element.find("input")["value"], "name": element.find("input")["name"], "type": type }) section_elements.append({ "type": type, "title": titleGroups.group("title") if not titleGroups is None else "", "description": row.find(attrs={ "class": "discreteCell" }).text.replace("\r", "").replace("\n", "").replace("\t", "").strip(), "number": titleGroups.group("number") if not titleGroups is None else "", "options": options, "section_id": section_id }) else: if not section_number is None: sections.append({ "number": section_number, "title": section_title, "elements": section_elements, "description": section_description }) section_number = None section_title = None section_elements = [] section_description = None lines = row.find("h3").text.replace("\t", "").replace( "\r", "").strip().split("\n") titleGroups = titleProg.match(str(lines[0]) + " " + str(lines[1])) section_number = titleGroups.group( "number") if not titleGroups is None else None section_title = titleGroups.group( "title") if not titleGroups is None else None section_description = row.find(attrs={ "class": "discreteCell" }).text.replace("\r\n", "").replace("\t", "").strip() if section_number == None: section_number = 1 section_title = "" section_description = "" sections.append({ "number": section_number, "title": section_title, "elements": section_elements, "description": section_description }) return {"status": "ok", "information": information, "sections": sections}
def message ( config, session = False ): url = "https://www.lectio.dk/lectio/%s/beskeder2.aspx?type=liste&elevid=%s" % ( str(config["school_id"]), str(config["student_id"]) ) if session is False: session = authenticate.authenticate(config) if session == False: return {"status" : "error", "type" : "authenticate"} # Insert the session information from the auth function cookies = { "lecmobile" : "0", "ASP.NET_SessionId" : session["ASP.NET_SessionId"], "LastLoginUserName" : session["LastLoginUserName"], "lectiogsc" : session["lectiogsc"], "LectioTicket" : session["LectioTicket"] } # Insert User-agent headers and the cookie information headers = { "User-Agent" : "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1665.2 Safari/537.36", "Content-Type" : "application/x-www-form-urlencoded", "Host" : "www.lectio.dk", "Origin" : "https://www.lectio.dk", "Cookie" : functions.implode(cookies, "{{index}}={{value}}", "; ") } response = proxy.session.get(url, headers=headers) html = response.text soup = Soup(html) viewStateX = soup.find("input", attrs={"id" : "__VIEWSTATEX"})["value"] settings = { "__EVENTTARGET" : "__Page", "__EVENTARGUMENT" : "$LB2$_MC_$_%s" % ( str(config["thread_id"]) ), "__VIEWSTATEX" : viewStateX, } response = proxy.session.post(url, data=settings, headers=headers) html = response.text soup = Soup(html) if soup.find("div", attrs={"id" : "s_m_Content_Content_ViewThreadPagePanel"}) is None: return { "status" : False, "error" : "Data not found" } flagged = False if soup.find("input", attrs={"id" : "s_m_Content_Content_FlagThisThreadBox"})["src"] == "/lectio/img/flagoff.gif" else True originalElements = soup.find("table", attrs={"class" : "ShowMessageRecipients"}).findAll("td") originalSenderUser = context_card.user({ "context_card_id" : originalElements[8].find("span")["lectiocontextcard"], "school_id" : config["school_id"] }, session) originalSenderUser["user"]["user_context_card_id"] = originalElements[8].find("span")["lectiocontextcard"] originalSenderUser["user"]["person_id"] = originalElements[8].find("span")["lectiocontextcard"].replace("U", "") originalSubject = unicode(functions.cleanText(originalElements[2].text)) recipients = [] studentRecipientProg = re.compile(r"(?P<name>.*) \((?P<student_class_id>.*)\)") teacherRecipientProg = re.compile(r"(?P<name>.*) \((?P<abbrevation>.*)\)") # Fill in the single users, added as recipients for row in originalElements[11].findAll("span"): context_card_id = row["lectiocontextcard"] userType = "" data = { "context_card_id" : context_card_id } if "S" in context_card_id: userType = "student" studentGroups = studentRecipientProg.match(row.text) data["person_id"] = context_card_id.replace("S", "") data["student_id"] = context_card_id.replace("S", "") data["name"] = unicode(studentGroups.group("name")) if not studentGroups is None else "" data["student_class_id"] = studentGroups.group("student_class_id") if not studentGroups is None else "" elif "T" in context_card_id: userType = "teacher" teacherGroups = teacherRecipientProg.match(row.text) data["person_id"] = context_card_id.replace("T", "") data["teacher_id"] = context_card_id.replace("T", "") data["abbrevation"] = unicode(teacherGroups.group("abbrevation")) if not teacherGroups is None else "" data["name"] = unicode(teacherGroups.group("name")) if not teacherGroups is None else "" data["type"] = userType recipients.append(data) row.decompose() recipientRows = originalElements[11].text.split(", ") for row in recipientRows: text = row.replace("\n", "").replace("\r", "").replace("\t", "") if "Holdet" in text: text = text.replace("Holdet ", "") recipients.append({ "type" : "team", "name" : unicode(text) }) elif "Gruppen" in text: text = text.replace("Gruppen ", "") recipients.append({ "type" : "group", "name" : unicode(text) }) messages = [] answerProg = re.compile(r"javascript:__doPostBack\('__Page','ANSWERMESSAGE_(?P<message_id>.*)'\);") dateTimeProg = re.compile(r"(?P<day>.*)\/(?P<month>.*)-(?P<year>.*) (?P<hour>.*):(?P<minute>.*)") messageLevels = {} for row in soup.find("table", attrs={"id" : "s_m_Content_Content_ThreadTable"}).findAll("tr"): if not row.find("table") is None: level = row.findAll(has_colspan)[0]["colspan"] data = {} messageDetailElements = row.find("table").findAll("td") # Subject data["subject"] = unicode(messageDetailElements[0].find("h4").text) messageDetailElements[0].find("h4").decompose() # Sender messageSender = context_card.user({ "context_card_id" : messageDetailElements[0].find("span")["lectiocontextcard"], "school_id" : config["school_id"] }, session) messageSender["user"]["user_context_card_id"] = originalElements[8].find("span")["lectiocontextcard"] messageSender["user"]["person_id"] = originalElements[8].find("span")["lectiocontextcard"].replace("U", "") data["sender"] = messageSender["user"] messageDetailElements[0].find("span").decompose() # Time timeText = messageDetailElements[0].text.replace("Af , ", "").strip().replace("\n", "").replace("\t", "") dateGroups = dateTimeProg.match(timeText) data["date"] = datetime.strptime("%s/%s-%s %s:%s" % (functions.zeroPadding(dateGroups.group("day")), functions.zeroPadding(dateGroups.group("month")), dateGroups.group("year"), dateGroups.group("hour"), dateGroups.group("minute")), "%d/%m-%Y %H:%M") if not dateGroups is None else "" # Message id answerGroups = answerProg.match(messageDetailElements[1].find("button")["onclick"]) message_id = answerGroups.group("message_id") if not answerGroups is None else "" data["message_id"] = message_id row.find("table").decompose() # Get message text data["message"] = unicode(row.text.strip()) # Get parent if str(int(level)+1) in messageLevels: data["parrent_id"] = messageLevels[str(int(level)+1)] messageLevels[level] = message_id messages.append(data) messageInfo = { "original_subject" : originalSubject, "flagged" : flagged, "original_sender" : originalSenderUser["user"], "recipients" : recipients, "messages" : messages } return { "status" : "ok", "message" : messageInfo, }