2
0

ExerciseGroups.Mod 62 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704
  1. MODULE ExerciseGroups; (** AUTHOR "Luc Blaeser"; PURPOSE "Web Accounts and Authorization Domains" *)
  2. IMPORT WebComplex, WebAccounts, WebStd, DynamicWebpage, PrevalenceSystem, HTTPSupport, HTTPSession,
  3. XML, XMLObjects, Strings, DynamicStrings, TFClasses, KernelLog;
  4. CONST
  5. SingleGroupDatagridName = "SingleGroupDatagrid";
  6. AllGroupsDatagridName = "AllGroupsDatagrid";
  7. ThisModuleNameStr = "ExerciseGroups";
  8. AllGroupsContainerPrefixName = "dxp-exercisegroups-allgroups-";
  9. PersonGradePrefixName = "dxp-grade-";
  10. NextButtonLabel = "Weiter";
  11. BackButtonLabel = "Zurueck";
  12. SearchText = "Suchen: ";
  13. EmptyListText = "Kein Eintrag";
  14. InsertGroupText = "Neue Gruppe erstellen";
  15. SubmitButtonLabel = "Speichern";
  16. UnapplySortLabel = "Sortierung aufheben";
  17. UnapplyFilterLabel = "Alle Eintraege anzeigen";
  18. ExerciseName = "Uebung ";
  19. EditExerciseGradesLabel = "Uebungsuebersicht anschauen";
  20. CloseExerciseGradesLabel = "Zurueck zur Liste der Uebungsgruppenmitglieder";
  21. EmailToTheWholeGroup = "E-Mail an die ganze Gruppe";
  22. AddNewExerciseLabel = "Neue Aufgabe einfuegen";
  23. DeleteAnExerciseLabel = "Aufgabe loeschen";
  24. SendGradeNotoficationLabel = "Student benachrichtigen";
  25. InsertToGroupLabel = "In Uebungsgruppe eintragen";
  26. GradeNotificationSubject = "Geloeste Uebungen";
  27. GradeNotificationSalutation = "Hallo";
  28. GradeNotificationBodyHead = "Du hast die folgende Anzahl Punkte in den Uebungen erreicht:";
  29. GradeNotificationBodyTail = "Tschuess";
  30. MailCR = "%0D%0A";
  31. TYPE
  32. (* wrapper integer object to use it for TFClasses.List *)
  33. IntObj = OBJECT
  34. VAR number: LONGINT;
  35. END IntObj;
  36. (* wrapper integer list using TFClasses.List *)
  37. IntList = OBJECT
  38. VAR
  39. list: TFClasses.List;
  40. locked: BOOLEAN;
  41. PROCEDURE &Init*;
  42. BEGIN NEW(list); locked := FALSE
  43. END Init;
  44. PROCEDURE GetCount() : LONGINT;
  45. BEGIN RETURN list.GetCount()
  46. END GetCount;
  47. (* returns 0 if item is not in the list *)
  48. PROCEDURE GetItem(pos: LONGINT) : LONGINT;
  49. VAR intObj: IntObj;
  50. BEGIN
  51. intObj := GetIntObj(pos);
  52. IF (intObj # NIL) THEN
  53. RETURN intObj.number
  54. ELSE
  55. RETURN 0
  56. END
  57. END GetItem;
  58. (* returns NIL if not in the list *)
  59. PROCEDURE GetIntObj(pos: LONGINT) : IntObj;
  60. VAR p: ANY; intObj: IntObj;
  61. BEGIN
  62. list.Lock;
  63. IF ((pos >= 0) & (pos < list.GetCount()))THEN
  64. p := list.GetItem(pos);
  65. list.Unlock;
  66. IF (p IS IntObj) THEN
  67. intObj := p(IntObj);
  68. RETURN intObj
  69. END
  70. ELSE
  71. list.Unlock
  72. END;
  73. RETURN NIL
  74. END GetIntObj;
  75. PROCEDURE Exchange(pos, newNumber: LONGINT);
  76. VAR intObj: IntObj;
  77. BEGIN
  78. intObj := GetIntObj(pos);
  79. IF (intObj # NIL) THEN
  80. intObj.number := newNumber
  81. END;
  82. END Exchange;
  83. PROCEDURE Add(newNumber: LONGINT);
  84. VAR intObj: IntObj;
  85. BEGIN
  86. Lock;
  87. NEW(intObj); intObj.number := newNumber;
  88. list.Add(intObj);
  89. Unlock
  90. END Add;
  91. PROCEDURE Remove(pos: LONGINT);
  92. VAR intObj: IntObj;
  93. BEGIN
  94. Lock;
  95. intObj := GetIntObj(pos);
  96. IF (intObj # NIL) THEN
  97. list.Remove(intObj);
  98. END;
  99. Unlock
  100. END Remove;
  101. PROCEDURE Lock;
  102. BEGIN {EXCLUSIVE}
  103. AWAIT(~locked); locked := TRUE
  104. END Lock;
  105. PROCEDURE Unlock;
  106. BEGIN {EXCLUSIVE}
  107. locked := FALSE
  108. END Unlock;
  109. END IntList;
  110. Person* = OBJECT(WebComplex.WebForumEntry);
  111. VAR
  112. firstname: Strings.String;
  113. lastname: Strings.String;
  114. email: Strings.String;
  115. leginr: Strings.String;
  116. grades: IntList;
  117. PROCEDURE Internalize*(input: XML.Content);
  118. VAR container: XML.Container; elem, subElem: XML.Element; p: ANY; enum: XMLObjects.Enumerator;
  119. str: Strings.String; number: LONGINT;
  120. BEGIN
  121. container := input(XML.Container);
  122. firstname := WebStd.InternalizeString(container, "FirstName");
  123. lastname := WebStd.InternalizeString(container, "LastName");
  124. email := WebStd.InternalizeString(container, "Email");
  125. leginr := WebStd.InternalizeString(container, "LegiNr");
  126. NEW(grades);
  127. elem := WebStd.GetXMLSubElement(container, "Grades");
  128. IF (elem # NIL) THEN
  129. enum := elem.GetContents();
  130. WHILE (enum.HasMoreElements()) DO
  131. p := enum.GetNext();
  132. IF (p IS XML.Element) THEN
  133. subElem := p(XML.Element);
  134. str := WebStd.GetXMLCharContent(subElem);
  135. IF (str # NIL) THEN
  136. Strings.StrToInt(str^, number);
  137. grades.Add(number)
  138. END
  139. END
  140. END
  141. END
  142. END Internalize;
  143. PROCEDURE Externalize*() : XML.Content;
  144. VAR container: XML.Container; elem, subElem: XML.Element; str: ARRAY 14 OF CHAR; i, number: LONGINT;
  145. BEGIN
  146. NEW(container);
  147. WebStd.ExternalizeString(firstname, container, "FirstName");
  148. WebStd.ExternalizeString(lastname, container, "LastName");
  149. WebStd.ExternalizeString(email, container, "Email");
  150. WebStd.ExternalizeString(leginr, container, "LegiNr");
  151. IF (grades # NIL) THEN
  152. NEW(elem); elem.SetName("Grades"); container.AddContent(elem);
  153. grades.Lock;
  154. FOR i := 0 TO grades.GetCount()-1 DO
  155. number := grades.GetItem(i);
  156. Strings.IntToStr(number, str);
  157. NEW(subElem); subElem.SetName("Grade"); elem.AddContent(subElem);
  158. WebStd.AppendXMLContent(subElem, WebStd.CreateXMLText(str))
  159. END;
  160. grades.Unlock
  161. END;
  162. RETURN container
  163. END Externalize;
  164. PROCEDURE TableView*(forum: WebComplex.WebForum; request: HTTPSupport.HTTPRequest) : WebComplex.TableRow;
  165. VAR row: WebComplex.TableRow;
  166. BEGIN
  167. NEW(row, 6);
  168. row[0] := WebComplex.GetTableCell(firstname, WebComplex.WebForumNormalCell);
  169. row[1] := WebComplex.GetTableCell(lastname, WebComplex.WebForumDetailViewCell);
  170. IF (IsAuthorizedUser(request)) THEN
  171. row[2] := WebComplex.GetEmailTableCell(email, WebComplex.WebForumNormalCell);
  172. row[3] := WebComplex.GetTableCell(leginr, WebComplex.WebForumNormalCell)
  173. ELSE
  174. row[2] := WebComplex.GetTableCellForText(" ", WebComplex.WebForumNormalCell);
  175. row[3] := WebComplex.GetTableCellForText(" ", WebComplex.WebForumNormalCell);
  176. END;
  177. row[4] := WebComplex.GetTableCellForText("Edit", WebComplex.WebForumEditViewCell);
  178. row[5] := WebComplex.GetTableCellForText("Delete", WebComplex.WebForumDeleteCell);
  179. RETURN row
  180. END TableView;
  181. PROCEDURE DetailView*(forum: WebComplex.WebForum; request: HTTPSupport.HTTPRequest) : XML.Content;
  182. VAR container: XML.Container; pTag: XML.Element;
  183. BEGIN
  184. NEW(container);
  185. NEW(pTag); pTag.SetName("p");
  186. WebStd.AppendXMLContent(pTag, WebStd.CreateXMLText("Name: "));
  187. IF (firstname # NIL) THEN
  188. WebStd.AppendXMLContent(pTag, WebStd.CreateXMLText(firstname^))
  189. END;
  190. IF (lastname # NIL) THEN
  191. WebStd.AppendXMLContent(pTag, WebStd.CreateXMLText(lastname^))
  192. END;
  193. container.AddContent(pTag);
  194. IF (IsAuthorizedUser(request)) THEN
  195. NEW(pTag); pTag.SetName("p");
  196. WebStd.AppendXMLContent(pTag, WebStd.CreateXMLText("Email: "));
  197. IF (email # NIL) THEN
  198. pTag.AddContent(WebComplex.GetMailtoElement(email^))
  199. END;
  200. container.AddContent(pTag);
  201. WebComplex.AddStandardDetailView(container, "Legi-Nr: ", leginr);
  202. WebStd.AppendXMLContent(container, GetGradesDetailView())
  203. END;
  204. RETURN container
  205. END DetailView;
  206. PROCEDURE GetGradesDetailView() : XML.Content;
  207. VAR table, tr, td: XML.Element; i, number: LONGINT; str: ARRAY 14 OF CHAR;
  208. BEGIN
  209. table := NIL;
  210. IF (grades # NIL) THEN
  211. grades.Lock;
  212. IF (grades.GetCount() > 0) THEN
  213. NEW(table); table.SetName("table");
  214. WebStd.AppendXMLContent(table, GetExerciseListHeaderRow(grades.GetCount()));
  215. NEW(tr); tr.SetName("tr"); table.AddContent(tr);
  216. FOR i := 0 TO grades.GetCount()-1 DO
  217. number := grades.GetItem(i); Strings.IntToStr(number, str);
  218. NEW(td); td.SetName("td"); tr.AddContent(td);
  219. WebStd.AppendXMLContent(td, WebStd.CreateXMLText(str))
  220. END
  221. END;
  222. grades.Unlock
  223. END;
  224. RETURN table
  225. END GetGradesDetailView;
  226. PROCEDURE EditView*(forum: WebComplex.WebForum; request: HTTPSupport.HTTPRequest) : XML.Content;
  227. VAR table: XML.Element;
  228. BEGIN
  229. NEW(table); table.SetName("table");
  230. WebComplex.AddTextFieldInputRow(table, "Vorname: ", "firstname", firstname);
  231. WebComplex.AddTextFieldInputRow(table, "Nachnahme: ", "lastname", lastname);
  232. WebComplex.AddTextFieldInputRow(table, "Email: ", "email", email);
  233. WebComplex.AddTextFieldInputRow(table, "Legi-Nr: ", "leginr", leginr);
  234. RETURN table
  235. END EditView;
  236. (* get XHTML table header row for the exercise grade list. *)
  237. PROCEDURE GetExerciseListHeaderRow(nofCols: LONGINT) : XML.Element;
  238. VAR tr, td: XML.Element; i: LONGINT; iStr: ARRAY 14 OF CHAR; str: Strings.String;
  239. BEGIN
  240. IF (nofCols > 0) THEN
  241. NEW(tr); tr.SetName("tr");
  242. FOR i := 1 TO nofCols DO
  243. NEW(td); td.SetName("td"); tr.AddContent(td);
  244. Strings.IntToStr(i, iStr);
  245. NEW(str, Strings.Length(ExerciseName)+LEN(iStr)+1);
  246. COPY(ExerciseName, str^); Strings.Append(str^, iStr);
  247. WebStd.AppendXMLContent(td, WebStd.CreateXMLText(str^));
  248. END
  249. ELSE
  250. tr := NIL
  251. END;
  252. RETURN tr
  253. END GetExerciseListHeaderRow;
  254. END Person;
  255. (** statefull active element as webforum but with a additional subelement 'MaxEntries' which specifies the
  256. * maximum number of members in a group
  257. <ExerciseGroups:SingleGroupDatagrid id=".." ..>
  258. ...
  259. <MaxEntries>13</MaxEntries>
  260. </ExerciseGroups:SingleGroupDatagrid>
  261. *)
  262. SingleGroupDatagrid* = OBJECT(WebComplex.WebForum);
  263. VAR
  264. searchText: Strings.String;
  265. maxEntries: LONGINT;
  266. PROCEDURE Transform*(input: XML.Element; request: HTTPSupport.HTTPRequest) : XML.Content;
  267. VAR maxEntriesStr: Strings.String; elem: XML.Element;
  268. BEGIN
  269. elem := WebStd.GetXMLSubElement(input, "MaxEntries");
  270. maxEntries := MAX(LONGINT);
  271. IF (elem # NIL) THEN
  272. maxEntriesStr := WebStd.GetXMLCharContent(elem);
  273. IF (maxEntriesStr # NIL) THEN
  274. Strings.StrToInt(maxEntriesStr^, maxEntries)
  275. END
  276. END;
  277. RETURN Transform^(input, request);
  278. END Transform;
  279. PROCEDURE GetHeaderXMLContent*(persContainer: WebStd.PersistentDataContainer; input: XML.Element;
  280. request: HTTPSupport.HTTPRequest) : XML.Content;
  281. VAR dynStr: DynamicStrings.DynamicString; list: WebStd.PersistentDataObjectList; i: LONGINT;
  282. str, encStr: Strings.String; person: Person; pTag, aTag: XML.Element; tempStr: ARRAY 10 OF CHAR;
  283. BEGIN (* email to the whole group *)
  284. IF ((IsAuthorizedUser(request)) & (persContainer # NIL)) THEN
  285. list := persContainer.GetElementList(WebStd.DefaultPersistentDataFilter, NIL);
  286. IF (list # NIL) THEN
  287. NEW(dynStr); COPY("mailto:", tempStr); dynStr.Append(tempStr);
  288. FOR i := 0 TO LEN(list)-1 DO
  289. IF ((list[i] #NIL) & (list[i] IS Person)) THEN
  290. person := list[i](Person);
  291. IF (person.email # NIL) THEN
  292. dynStr.Append(person.email^);
  293. IF (i < LEN(list)-1) THEN
  294. COPY(",", tempStr); dynStr.Append(tempStr)
  295. END
  296. END
  297. END
  298. END;
  299. str := dynStr.ToArrOfChar(); (* str # NIL *)
  300. NEW(pTag); pTag.SetName("p");
  301. NEW(aTag); aTag.SetName("a"); pTag.AddContent(aTag);
  302. encStr := WebStd.GetEncXMLAttributeText(str^); (* encStr # NIL *)
  303. aTag.SetAttributeValue("href", encStr^);
  304. WebStd.AppendXMLContent(aTag, WebStd.CreateXMLText(EmailToTheWholeGroup));
  305. RETURN pTag
  306. END
  307. END;
  308. RETURN NIL
  309. END GetHeaderXMLContent;
  310. PROCEDURE InsertObject*(container: WebStd.PersistentDataContainer; superEntry: WebComplex.WebForumEntry;
  311. request: HTTPSupport.HTTPRequest; params: DynamicWebpage.ParameterList; VAR statusMsg: XML.Content) : BOOLEAN;
  312. (* parameters "firstname", "lastname", "email", "leginr"*)
  313. VAR firstname, lastname, email, leginr: Strings.String; obj: Person;
  314. BEGIN
  315. firstname := params.GetParameterValueByName("firstname");
  316. lastname := params.GetParameterValueByName("lastname");
  317. email := params.GetParameterValueByName("email");
  318. leginr := params.GetParameterValueByName("leginr");
  319. IF (container.GetCount() >= maxEntries) THEN
  320. statusMsg := WebStd.CreateXMLText(" Maxmimale Anzahl Leute pro Gruppe bereits ueberschritten.");
  321. RETURN FALSE
  322. ELSIF ((firstname = NIL) OR (firstname^ = "")) THEN
  323. statusMsg := WebStd.CreateXMLText(" Vorname fehlt");
  324. RETURN FALSE
  325. ELSIF ((lastname = NIL) OR (lastname^ = "")) THEN
  326. statusMsg := WebStd.CreateXMLText("Nachnahme fehlt");
  327. RETURN FALSE
  328. ELSIF ((email = NIL) OR (email ^ = "")) THEN
  329. statusMsg := WebStd.CreateXMLText("E-Mail fehlt");
  330. RETURN FALSE
  331. ELSIF ((leginr = NIL) OR (leginr ^ = "")) THEN
  332. statusMsg := WebStd.CreateXMLText("Legi Nummer fehlt");
  333. RETURN FALSE
  334. ELSE
  335. NEW(obj); obj.firstname := firstname; obj.lastname := lastname; obj.email := email; obj.leginr := leginr;
  336. container.AddPersistentDataObject(obj, personDesc); (* adds it also to the prevalence system *)
  337. RETURN TRUE
  338. END
  339. END InsertObject;
  340. PROCEDURE UpdateObject*(obj: WebComplex.WebForumEntry; request: HTTPSupport.HTTPRequest;
  341. params: DynamicWebpage.ParameterList; VAR statusMsg: XML.Content) : BOOLEAN;
  342. VAR firstname, lastname, email, leginr: Strings.String; person: Person;
  343. BEGIN (* obj # NIL *)
  344. IF (obj IS Person) THEN
  345. person := obj(Person);
  346. firstname := params.GetParameterValueByName("firstname");
  347. lastname := params.GetParameterValueByName("lastname");
  348. email := params.GetParameterValueByName("email");
  349. leginr := params.GetParameterValueByName("leginr");
  350. IF ((firstname = NIL) OR (firstname^ = "")) THEN
  351. statusMsg := WebStd.CreateXMLText("Vornahme is missing");
  352. RETURN FALSE
  353. ELSIF ((lastname = NIL) OR (lastname^ = "")) THEN
  354. statusMsg := WebStd.CreateXMLText("Nachnahme fehlt");
  355. RETURN FALSE
  356. ELSIF ((email = NIL) OR (email ^ = "")) THEN
  357. statusMsg := WebStd.CreateXMLText("Email fehlt");
  358. RETURN FALSE
  359. ELSIF ((leginr = NIL) OR (leginr ^ = "")) THEN
  360. statusMsg := WebStd.CreateXMLText("Legi Nummer fehlt");
  361. RETURN FALSE
  362. END;
  363. person.BeginModification;
  364. person.firstname := firstname;
  365. person.lastname := lastname;
  366. person.email := email;
  367. person.leginr := leginr;
  368. person.EndModification;
  369. RETURN TRUE
  370. ELSE
  371. statusMsg := WebStd.CreateXMLText("object is not of type Person");
  372. RETURN FALSE
  373. END
  374. END UpdateObject;
  375. PROCEDURE ThisObjectName*() : Strings.String;
  376. BEGIN
  377. RETURN WebStd.GetString(SingleGroupDatagridName)
  378. END ThisObjectName;
  379. PROCEDURE ThisModuleName*() : Strings.String;
  380. BEGIN
  381. RETURN WebStd.GetString(ThisModuleNameStr)
  382. END ThisModuleName;
  383. (** returns the insert view for the initialization of a new web forum entry, without submit/back-input fields
  384. * and without hidden parameter for super entry in hierarchy.
  385. * superEntry is the parent web forum entry in a hierachical web forum, superEntry is NIL iff it is a root entry *)
  386. PROCEDURE GetInsertView*(superEntry: WebComplex.WebForumEntry; request: HTTPSupport.HTTPRequest): XML.Content;
  387. VAR table: XML.Element;
  388. BEGIN
  389. NEW(table); table.SetName("table");
  390. WebComplex.AddTextFieldInputRow(table, "First name:", "firstname", NIL);
  391. WebComplex.AddTextFieldInputRow(table, "Last name:", "lastname", NIL);
  392. WebComplex.AddTextFieldInputRow(table, "Email: ", "email", NIL);
  393. WebComplex.AddTextFieldInputRow(table, "Legi-Nr: ", "leginr", NIL);
  394. RETURN table
  395. END GetInsertView;
  396. PROCEDURE GetTableHeader*(request: HTTPSupport.HTTPRequest): WebComplex.HeaderRow;
  397. VAR row: WebComplex.HeaderRow;
  398. BEGIN
  399. NEW(row, 6);
  400. row[0] := WebComplex.GetHeaderCellForText("Vorname", CompareFirstName);
  401. row[1] := WebComplex.GetHeaderCellForText("Nachnahme", CompareLastName);
  402. IF (IsAuthorizedUser(request)) THEN
  403. row[2] := WebComplex.GetHeaderCellForText("Email", CompareEmail);
  404. row[3] := WebComplex.GetHeaderCellForText("Legi Nummer", CompareLegiNr)
  405. ELSE
  406. row[2] := WebComplex.GetHeaderCellForText(" ", NIL);
  407. row[3] := WebComplex.GetHeaderCellForText(" ", NIL);
  408. END;
  409. row[4] := WebComplex.GetHeaderCellForText(" ", NIL);
  410. row[5] := WebComplex.GetHeaderCellForText(" ", NIL);
  411. RETURN row
  412. END GetTableHeader;
  413. PROCEDURE GetSearchFilter*(text: Strings.String) : WebStd.PersistentDataFilter;
  414. BEGIN
  415. IF (text # NIL) THEN
  416. NEW(searchText, Strings.Length(text^)+3);
  417. Strings.Concat("*", text^, searchText^);
  418. IF (Strings.Length(text^) > 0) THEN
  419. Strings.Append(searchText^, "*");
  420. Strings.LowerCase(searchText^)
  421. END;
  422. RETURN SearchFilter
  423. END;
  424. RETURN NIL
  425. END GetSearchFilter;
  426. PROCEDURE SearchFilter(obj: WebStd.PersistentDataObject) : BOOLEAN;
  427. VAR entry: Person;
  428. PROCEDURE Matches(VAR str: ARRAY OF CHAR) : BOOLEAN;
  429. VAR lowStr: Strings.String;
  430. BEGIN
  431. lowStr := WebStd.GetString(str);
  432. Strings.LowerCase(lowStr^);
  433. RETURN Strings.Match(searchText^, lowStr^)
  434. END Matches;
  435. BEGIN (* searchText # NIL *)
  436. IF (obj IS Person) THEN
  437. entry := obj(Person);
  438. IF ((entry.firstname # NIL) & (Matches(entry.firstname^))) THEN
  439. RETURN TRUE
  440. END;
  441. IF ((entry.lastname # NIL) & (Matches(entry.lastname^))) THEN
  442. RETURN TRUE
  443. END;
  444. IF ((entry.email # NIL) & (Matches(entry.email^))) THEN
  445. RETURN TRUE
  446. END;
  447. IF ((entry.leginr # NIL) & (Matches(entry.leginr^))) THEN
  448. RETURN TRUE
  449. END;
  450. END;
  451. RETURN FALSE
  452. END SearchFilter;
  453. PROCEDURE GetDefaultOrdering*() : WebStd.PersistentDataCompare;
  454. BEGIN RETURN CompareLastName
  455. END GetDefaultOrdering;
  456. PROCEDURE GetEmptyListMessage*(request: HTTPSupport.HTTPRequest) : XML.Container;
  457. BEGIN
  458. RETURN WebStd.CreateXMLText(EmptyListText);
  459. END GetEmptyListMessage;
  460. PROCEDURE GetBackButtonLabel*(request: HTTPSupport.HTTPRequest) : Strings.String;
  461. BEGIN RETURN WebStd.GetString(BackButtonLabel)
  462. END GetBackButtonLabel;
  463. PROCEDURE GetInsertLinkLabel*(request: HTTPSupport.HTTPRequest) : Strings.String;
  464. BEGIN RETURN WebStd.GetString(InsertToGroupLabel);
  465. END GetInsertLinkLabel;
  466. PROCEDURE GetSubmitButtonLabel*(request: HTTPSupport.HTTPRequest): Strings.String;
  467. BEGIN RETURN WebStd.GetString(SubmitButtonLabel)
  468. END GetSubmitButtonLabel;
  469. PROCEDURE GetUnapplySortLabel*(request: HTTPSupport.HTTPRequest): Strings.String;
  470. BEGIN RETURN WebStd.GetString(UnapplySortLabel)
  471. END GetUnapplySortLabel;
  472. PROCEDURE GetUnapplyFilterLabel*(request: HTTPSupport.HTTPRequest): Strings.String;
  473. BEGIN RETURN WebStd.GetString(UnapplyFilterLabel)
  474. END GetUnapplyFilterLabel;
  475. PROCEDURE CompareFirstName(obj1, obj2: WebStd.PersistentDataObject): BOOLEAN;
  476. VAR f1, f2: Person;
  477. BEGIN
  478. IF ((obj1 IS Person) & (obj2 IS Person)) THEN
  479. f1 := obj1(Person); f2 := obj2(Person);
  480. IF (f2.firstname = NIL) THEN
  481. RETURN FALSE
  482. ELSIF (f1.firstname = NIL) THEN (* f2.firstname # NIL *)
  483. RETURN TRUE
  484. ELSE
  485. RETURN f1.firstname^ < f2.firstname^
  486. END
  487. ELSE
  488. RETURN FALSE
  489. END
  490. END CompareFirstName;
  491. PROCEDURE CompareEmail(obj1, obj2: WebStd.PersistentDataObject): BOOLEAN;
  492. VAR f1, f2: Person;
  493. BEGIN
  494. IF ((obj1 IS Person) & (obj2 IS Person)) THEN
  495. f1 := obj1(Person); f2 := obj2(Person);
  496. IF (f2.email = NIL) THEN
  497. RETURN FALSE
  498. ELSIF (f1.email = NIL) THEN (* f2.email # NIL *)
  499. RETURN TRUE
  500. ELSE
  501. RETURN f1.email^ < f2.email^
  502. END
  503. ELSE
  504. RETURN FALSE
  505. END
  506. END CompareEmail;
  507. PROCEDURE CompareLegiNr(obj1, obj2: WebStd.PersistentDataObject): BOOLEAN;
  508. VAR f1, f2: Person;
  509. BEGIN
  510. IF ((obj1 IS Person) & (obj2 IS Person)) THEN
  511. f1 := obj1(Person); f2 := obj2(Person);
  512. IF (f2.leginr = NIL) THEN
  513. RETURN FALSE
  514. ELSIF (f1.leginr = NIL) THEN (* f2.leginr # NIL *)
  515. RETURN TRUE
  516. ELSE
  517. RETURN f1.leginr^ < f2.leginr^
  518. END
  519. ELSE
  520. RETURN FALSE
  521. END
  522. END CompareLegiNr;
  523. END SingleGroupDatagrid;
  524. Group* = OBJECT(WebComplex.WebForumEntry);
  525. VAR
  526. name: Strings.String;
  527. assistant: Strings.String;
  528. date: Strings.String;
  529. place: Strings.String;
  530. info: Strings.String;
  531. openToJoin: BOOLEAN; (* true if public insertion to the group is possible *)
  532. maxPeople: LONGINT; (* maximum number of group members *)
  533. members: WebStd.PersistentDataContainer; (* PersistentDataContainer of Person *)
  534. membersDgId: Strings.String; (* id of the members single group web datagrid *)
  535. gradesEditListId: Strings.String; (* id of the grades edit list for the members exercises *)
  536. toggleBlockId: Strings.String; (* id of the toggle block in the detail view *)
  537. PROCEDURE &Initialize*;
  538. BEGIN Init; (* call super initializer *)
  539. membersDgId := DynamicWebpage.CreateNewObjectId(); (* membersDgId # NIL *)
  540. gradesEditListId := DynamicWebpage.CreateNewObjectId(); (* gradesEditListId # NIL *)
  541. toggleBlockId := DynamicWebpage.CreateNewObjectId() (* toggleBlockId # NIL *)
  542. END Initialize;
  543. PROCEDURE Internalize*(input: XML.Content);
  544. VAR container: XML.Container; elem: XML.Element; oidStr: Strings.String;
  545. persObj: PrevalenceSystem.PersistentObject; oidNr: LONGINT;
  546. BEGIN
  547. container := input(XML.Container);
  548. (* element specific fields *)
  549. elem := WebStd.GetXMLSubElement(container, "Members");
  550. members := NIL;
  551. IF (elem # NIL) THEN
  552. oidStr := WebStd.GetXMLCharContent(elem);
  553. IF (oidStr # NIL) THEN
  554. Strings.StrToInt(oidStr^, oidNr);
  555. persObj := PrevalenceSystem.GetPersistentObject(oidNr);
  556. IF ((persObj # NIL) & (persObj IS WebStd.PersistentDataContainer)) THEN
  557. members := persObj(WebStd.PersistentDataContainer)
  558. ELSE
  559. HALT(9999)
  560. END
  561. END
  562. END;
  563. name := WebStd.InternalizeString(container, "Name");
  564. info := WebStd.InternalizeString(container, "Info");
  565. assistant := WebStd.InternalizeString(container, "Assistant");
  566. date := WebStd.InternalizeString(container, "Date");
  567. place := WebStd.InternalizeString(container, "Place");
  568. openToJoin := WebStd.InternalizeBoolean(container, "Open");
  569. maxPeople := WebStd.InternalizeInteger(container, "MaxPeople");
  570. END Internalize;
  571. PROCEDURE Externalize*() : XML.Content;
  572. VAR container: XML.Container; elem: XML.Element; oidStr: ARRAY 14 OF CHAR;
  573. BEGIN
  574. NEW(container);
  575. (* element specific fields *)
  576. IF (members # NIL) THEN
  577. NEW(elem); elem.SetName("Members");
  578. Strings.IntToStr(members.oid, oidStr);
  579. WebStd.AppendXMLContent(elem, WebStd.CreateXMLText(oidStr));
  580. container.AddContent(elem)
  581. END;
  582. WebStd.ExternalizeString(name, container, "Name");
  583. WebStd.ExternalizeString(info, container, "Info");
  584. WebStd.ExternalizeString(assistant, container, "Assistant");
  585. WebStd.ExternalizeString(date, container, "Date");
  586. WebStd.ExternalizeString(place, container, "Place");
  587. WebStd.ExternalizeBoolean(openToJoin, container, "Open");
  588. WebStd.ExternalizeInteger(maxPeople, container, "MaxPeople");
  589. RETURN container
  590. END Externalize;
  591. PROCEDURE GetReferrencedObjects*() : PrevalenceSystem.PersistentObjectList;
  592. VAR list: PrevalenceSystem.PersistentObjectList;
  593. BEGIN
  594. NEW(list, 1);
  595. list[0] := members;
  596. RETURN list
  597. END GetReferrencedObjects;
  598. PROCEDURE UpdateGrade(personOid, exerciseNo, newGrade: LONGINT);
  599. VAR list: WebStd.PersistentDataObjectList; person: Person; i, oldGrade: LONGINT;
  600. BEGIN
  601. IF (members # NIL) THEN
  602. list := members.GetElementList(WebStd.DefaultPersistentDataFilter, NIL);
  603. IF (list # NIL) THEN
  604. FOR i := 0 TO LEN(list)-1 DO
  605. IF ((list[i].oid = personOid) & (list[i] IS Person)) THEN
  606. person := list[i](Person);
  607. IF (person.grades # NIL) THEN
  608. oldGrade := person.grades.GetItem(exerciseNo);
  609. IF (oldGrade # newGrade) THEN
  610. person.BeginModification;
  611. person.grades.Exchange(exerciseNo, newGrade);
  612. person.EndModification
  613. END
  614. END
  615. END
  616. END
  617. END
  618. END
  619. END UpdateGrade;
  620. (* returns the number of free places as string # NIL *)
  621. PROCEDURE GetFreePlaces() : Strings.String;
  622. VAR free: LONGINT; maxPeopleStr: Strings.String;
  623. BEGIN
  624. IF (members # NIL) THEN
  625. free := maxPeople-members.GetCount()
  626. ELSE
  627. free := maxPeople;
  628. END;
  629. NEW(maxPeopleStr, 14); Strings.IntToStr(free, maxPeopleStr^);
  630. RETURN maxPeopleStr
  631. END GetFreePlaces;
  632. PROCEDURE TableView*(forum: WebComplex.WebForum; request: HTTPSupport.HTTPRequest) : WebComplex.TableRow;
  633. VAR row: WebComplex.TableRow;
  634. BEGIN
  635. NEW(row, 8);
  636. row[0] := WebComplex.GetTableCell(name, WebComplex.WebForumDetailViewCell);
  637. row[1] := WebComplex.GetTableCell(assistant, WebComplex.WebForumNormalCell);
  638. row[2] := WebComplex.GetTableCell(date, WebComplex.WebForumNormalCell);
  639. row[3] := WebComplex.GetTableCell(place, WebComplex.WebForumNormalCell);
  640. row[4] := WebComplex.GetTableCell(info, WebComplex.WebForumNormalCell);
  641. row[5] := WebComplex.GetTableCell(GetFreePlaces(), WebComplex.WebForumNormalCell);
  642. row[6] := WebComplex.GetTableCellForText("Aendern", WebComplex.WebForumEditViewCell);
  643. row[7] := WebComplex.GetTableCellForText("Loeschen", WebComplex.WebForumDeleteCell);
  644. RETURN row
  645. END TableView;
  646. PROCEDURE DetailView*(forum: WebComplex.WebForum; request: HTTPSupport.HTTPRequest) : XML.Content;
  647. VAR container: XML.Container; toggleBlock, show, hide: XML.Element;
  648. BEGIN
  649. NEW(container);
  650. WebComplex.AddStandardDetailView(container, "Name: ", name);
  651. WebComplex.AddStandardDetailView(container, "Assistent: ", assistant);
  652. WebComplex.AddStandardDetailView(container, "Zeit: ", date);
  653. WebComplex.AddStandardDetailView(container, "Ort: ", place);
  654. WebComplex.AddStandardDetailView(container, "Information: ", info);
  655. WebComplex.AddStandardDetailView(container, "Freie Plaetze: ", GetFreePlaces());
  656. IF ((forum # NIL) & (forum.allowEdit)) THEN
  657. (* use active element
  658. * <WebStd:ToggleBlock id=".." startWith="Hide" showLabel="$EditExerciseGradesLabel"
  659. hideLabel="$CloseExerciseGradesLabel">
  660. <Show>
  661. GetGradesEditListView(..)
  662. </Show>
  663. <Hide>
  664. GetSingleGroupDatagridView(..)
  665. </Hide>
  666. </WebStd:ToggleBlock> *)
  667. NEW(toggleBlock); toggleBlock.SetName("WebStd:ToggleBlock"); container.AddContent(toggleBlock);
  668. toggleBlock.SetAttributeValue("xmlns:WebStd", "WebStd");
  669. toggleBlock.SetAttributeValue("id", toggleBlockId^);
  670. toggleBlock.SetAttributeValue("startWith", "Hide");
  671. toggleBlock.SetAttributeValue("showLabel", EditExerciseGradesLabel);
  672. toggleBlock.SetAttributeValue("hideLabel", CloseExerciseGradesLabel);
  673. NEW(show); show.SetName("Show"); toggleBlock.AddContent(show);
  674. WebStd.AppendXMLContent(show, GetGradesEditListView(forum, request));
  675. NEW(hide); hide.SetName("Hide"); toggleBlock.AddContent(hide);
  676. WebStd.AppendXMLContent(hide, GetSingleGroupDatagridView(forum, request));
  677. ELSE
  678. WebStd.AppendXMLContent(container, GetSingleGroupDatagridView(forum, request));
  679. END;
  680. RETURN container
  681. END DetailView;
  682. PROCEDURE GetGradesEditListView(forum: WebComplex.WebForum; request: HTTPSupport.HTTPRequest) : XML.Content;
  683. VAR table, tr, td, gradesEditList: XML.Element; groupOidStr: ARRAY 14 OF CHAR;
  684. BEGIN
  685. IF ((forum # NIL) & (forum.allowEdit)) THEN
  686. NEW(table); table.SetName("table"); table.SetAttributeValue("border", "1");
  687. NEW(tr); tr.SetName("tr"); table.AddContent(tr);
  688. NEW(td); td.SetName("td"); tr.AddContent(td);
  689. (* display grades edit list *)
  690. (* use active element
  691. * <ExerciseGroups:GradesEditList id=".." groupoid=".." prevalencesystem=".."/> *)
  692. Strings.IntToStr(SELF.oid, groupOidStr);
  693. NEW(gradesEditList); gradesEditList.SetName("ExerciseGroups:GradesEditList");
  694. gradesEditList.SetAttributeValue("xmlns:ExerciseGroups", ThisModuleNameStr);
  695. gradesEditList.SetAttributeValue("id", gradesEditListId^);
  696. gradesEditList.SetAttributeValue("groupoid", groupOidStr);
  697. td.AddContent(gradesEditList);
  698. RETURN table
  699. ELSE
  700. RETURN NIL
  701. END
  702. END GetGradesEditListView;
  703. PROCEDURE GetSingleGroupDatagridView(forum: WebComplex.WebForum; request: HTTPSupport.HTTPRequest) : XML.Content;
  704. VAR table, tr, td, accountDg, searching, accessConstraint, edit, insert, delete, denied, maxEntries: XML.Element;
  705. membersName: Strings.String; allGroupsDg: AllGroupsDatagrid; maxPeopleStr: ARRAY 14 OF CHAR;
  706. BEGIN
  707. IF (members # NIL) THEN
  708. membersName := members.GetName();
  709. IF (membersName # NIL) THEN
  710. NEW(table); table.SetName("table"); table.SetAttributeValue("border", "1");
  711. NEW(tr); tr.SetName("tr"); table.AddContent(tr);
  712. NEW(td); td.SetName("td"); tr.AddContent(td);
  713. (* use active element
  714. * <ExerciseGroups:SingleGroupDatagrid id=".." containername=".." prevalencesystem=".." [reinitilize="true"]>
  715. * <Searching label=".."/>
  716. * <AccessConstraint>..</AccessConstraint>
  717. * </ExerciseGroups:SingleGroupDatagrid>
  718. * access constraint is the same for the actual datagrid
  719. *)
  720. NEW(accountDg); accountDg.SetName("ExerciseGroups:SingleGroupDatagrid");
  721. accountDg.SetAttributeValue("xmlns:ExerciseGroups", ThisModuleNameStr);
  722. accountDg.SetAttributeValue("id", membersDgId^);
  723. accountDg.SetAttributeValue("containername", membersName^);
  724. (*
  725. NEW(paging); paging.SetName("Paging"); accountDg.AddContent(paging);
  726. paging.SetAttributeValue("size", "10");
  727. paging.SetAttributeValue("nextlabel", NextButtonLabel);
  728. paging.SetAttributeValue("previouslabel", BackButtonLabel);
  729. *)
  730. NEW(searching); searching.SetName("Searching"); accountDg.AddContent(searching);
  731. searching.SetAttributeValue("label", SearchText);
  732. NEW(maxEntries); maxEntries.SetName("MaxEntries"); accountDg.AddContent(maxEntries);
  733. Strings.IntToStr(maxPeople, maxPeopleStr);
  734. WebStd.AppendXMLContent(maxEntries, WebStd.CreateXMLText(maxPeopleStr));
  735. NEW(accessConstraint); accessConstraint.SetName("AccessConstraint"); accountDg.AddContent(accessConstraint);
  736. insert := NIL; edit := NIL; delete := NIL;
  737. IF ((forum # NIL) & (forum IS AllGroupsDatagrid)) THEN
  738. allGroupsDg := forum(AllGroupsDatagrid);
  739. IF (allGroupsDg.accessConstraint # NIL) THEN
  740. insert := WebStd.GetXMLSubElement(allGroupsDg.accessConstraint, "Insert");
  741. edit := WebStd.GetXMLSubElement(allGroupsDg.accessConstraint, "Edit");
  742. delete := WebStd.GetXMLSubElement(allGroupsDg.accessConstraint, "Delete")
  743. END;
  744. (* user could have used the back button in the browser's navigation bar, therefore reinitialize subcontainer
  745. * if detail view has just been activated *)
  746. IF (allGroupsDg.reInitializeSubContainer) THEN
  747. accountDg.SetAttributeValue("reinitialize", "true")
  748. END;
  749. allGroupsDg.reInitializeSubContainer := FALSE
  750. END;
  751. IF (openToJoin) THEN
  752. (* allow public insertion to the group, delete access constraint *)
  753. insert := NIL
  754. END;
  755. IF ((members # NIL) & (members.GetCount() >= maxPeople)) THEN
  756. (* deny insertion *)
  757. NEW(insert); insert.SetName("Insert");
  758. NEW(denied); denied.SetName("Denied"); insert.AddContent(denied)
  759. END;
  760. IF (insert # NIL) THEN
  761. accessConstraint.AddContent(insert)
  762. END;
  763. IF (edit # NIL) THEN
  764. accessConstraint.AddContent(edit)
  765. END;
  766. IF (delete # NIL) THEN
  767. accessConstraint.AddContent(delete)
  768. END;
  769. td.AddContent(accountDg);
  770. RETURN table
  771. ELSE
  772. RETURN WebStd.CreateXMLText("no members container name defined.")
  773. END
  774. ELSE
  775. RETURN WebStd.CreateXMLText("no members container present.")
  776. END
  777. END GetSingleGroupDatagridView;
  778. PROCEDURE EditView*(forum: WebComplex.WebForum; request: HTTPSupport.HTTPRequest) : XML.Content;
  779. VAR table, tr, td, select, option: XML.Element; maxPeopleStr: Strings.String;
  780. BEGIN
  781. NEW(table); table.SetName("table");
  782. WebComplex.AddTextFieldInputRow(table, "Name", "name", name);
  783. WebComplex.AddTextFieldInputRow(table, "Assistent: ", "assistant", assistant);
  784. WebComplex.AddTextFieldInputRow(table, "Zeit: ", "date", date);
  785. WebComplex.AddTextFieldInputRow(table, "Ort: ", "place", place);
  786. WebComplex.AddTextFieldInputRow(table, "Information: ", "info", info);
  787. NEW(maxPeopleStr, 14); Strings.IntToStr(maxPeople, maxPeopleStr^);
  788. WebComplex.AddTextFieldInputRow(table, "Maxmimale Platze: ", "maxpeople", maxPeopleStr);
  789. NEW(tr); tr.SetName("tr"); table.AddContent(tr);
  790. NEW(td); td.SetName("td"); tr.AddContent(td);
  791. WebStd.AppendXMLContent(td, WebStd.CreateXMLText("Offen zum Einschreiben: "));
  792. NEW(td); td.SetName("td"); tr.AddContent(td);
  793. NEW(select); select.SetName("select"); td.AddContent(select);
  794. select.SetAttributeValue("name", "opentojoin");
  795. NEW(option); option.SetName("option"); select.AddContent(option);
  796. option.SetAttributeValue("value", "true");
  797. WebStd.AppendXMLContent(option, WebStd.CreateXMLText("Ja"));
  798. IF (openToJoin) THEN option.SetAttributeValue("selected", "true") END;
  799. NEW(option); option.SetName("option"); select.AddContent(option);
  800. option.SetAttributeValue("value", "false");
  801. WebStd.AppendXMLContent(option, WebStd.CreateXMLText("Nein"));
  802. IF (~openToJoin) THEN option.SetAttributeValue("selected", "true") END;
  803. RETURN table
  804. END EditView;
  805. (* add a new exercise for all group members and initialize their grade for this new exercise with 0 *)
  806. PROCEDURE AddNewExercise;
  807. VAR list: WebStd.PersistentDataObjectList; i: LONGINT; person: Person;
  808. BEGIN
  809. IF (members # NIL) THEN
  810. list := members.GetElementList(WebStd.DefaultPersistentDataFilter, NIL);
  811. FOR i := 0 TO LEN(list)-1 DO
  812. IF (list[i] IS Person) THEN
  813. person := list[i](Person);
  814. person.BeginModification;
  815. IF (person.grades = NIL) THEN NEW(person.grades) END;
  816. person.grades.Add(0);
  817. person.EndModification
  818. END
  819. END
  820. END
  821. END AddNewExercise;
  822. (* delete the exercise number 'pos' for all group members *)
  823. PROCEDURE DeleteExercise(pos: LONGINT);
  824. VAR list: WebStd.PersistentDataObjectList; i: LONGINT; person: Person;
  825. BEGIN
  826. IF (members # NIL) THEN
  827. list := members.GetElementList(WebStd.DefaultPersistentDataFilter, NIL);
  828. FOR i := 0 TO LEN(list)-1 DO
  829. IF (list[i] IS Person) THEN
  830. person := list[i](Person);
  831. IF (person.grades # NIL) THEN
  832. person.BeginModification;
  833. person.grades.Remove(pos);
  834. person.EndModification
  835. END
  836. END
  837. END
  838. END
  839. END DeleteExercise;
  840. END Group;
  841. (** statefull active element *)
  842. AllGroupsDatagrid* = OBJECT(WebComplex.WebForum);
  843. VAR
  844. searchText: Strings.String;
  845. accessConstraint: XML.Element; (* used for nested datagrid *)
  846. reInitializeSubContainer: BOOLEAN; (* true if the subcontainer has to be reinitialized*)
  847. (* user could use the back button in browser's navigation bar *)
  848. PROCEDURE &Init*;
  849. BEGIN Init^; reInitializeSubContainer := FALSE
  850. END Init;
  851. PROCEDURE Transform*(input: XML.Element; request: HTTPSupport.HTTPRequest) : XML.Content;
  852. BEGIN
  853. (* get the access constraint for later propagation to the nested SingleGroupDatagrid *)
  854. accessConstraint := WebStd.GetXMLSubElement(input, "AccessConstraint");
  855. RETURN Transform^(input, request)
  856. END Transform;
  857. PROCEDURE InsertObject*(container: WebStd.PersistentDataContainer; superEntry: WebComplex.WebForumEntry;
  858. request: HTTPSupport.HTTPRequest; params: DynamicWebpage.ParameterList; VAR statusMsg: XML.Content) : BOOLEAN;
  859. (* parameters "name", "info", "assistant", "date", "place", "maxpeople", "opentojoin" *)
  860. VAR name, info, assistant, date, place, maxpeople, opentojoin, containername: Strings.String; obj: Group;
  861. BEGIN
  862. name := params.GetParameterValueByName("name");
  863. info := params.GetParameterValueByName("info");
  864. assistant := params.GetParameterValueByName("assistant");
  865. date := params.GetParameterValueByName("date");
  866. place := params.GetParameterValueByName("place");
  867. maxpeople := params.GetParameterValueByName("maxpeople");
  868. opentojoin := params.GetParameterValueByName("opentojoin");
  869. IF ((name # NIL) & (name^ # "")) THEN
  870. NEW(containername, Strings.Length(name^)+Strings.Length(AllGroupsContainerPrefixName)+1);
  871. Strings.Concat(AllGroupsContainerPrefixName, name^, containername^);
  872. (* check conflict with another container *)
  873. IF (WebStd.FindPersistentDataContainer(PrevalenceSystem.standardPrevalenceSystem, containername^) # NIL) THEN
  874. statusMsg := WebStd.CreateXMLText("Gruppenname bereits verwendet");
  875. RETURN FALSE
  876. END;
  877. NEW(obj); obj.name := name; obj.info := info; obj.assistant := assistant; obj.date := date; obj.place := place;
  878. IF (maxpeople # NIL) THEN
  879. Strings.StrToInt(maxpeople^, obj.maxPeople)
  880. ELSE
  881. obj.maxPeople := 0
  882. END;
  883. IF ((opentojoin # NIL) & (opentojoin^ = "true")) THEN
  884. obj.openToJoin := TRUE
  885. ELSE
  886. obj.openToJoin := FALSE
  887. END;
  888. container.AddPersistentDataObject(obj, groupDesc); (* adds it also to the prevalence system *)
  889. obj.BeginModification;
  890. NEW(obj.members);
  891. PrevalenceSystem.AddPersistentObject(obj.members, WebStd.persistentDataContainerDesc);
  892. obj.EndModification;
  893. obj.members.SetName(containername^);
  894. RETURN TRUE
  895. ELSE
  896. statusMsg := WebStd.CreateXMLText("Name fehlt");
  897. RETURN FALSE
  898. END
  899. END InsertObject;
  900. PROCEDURE UpdateObject*(obj: WebComplex.WebForumEntry; request: HTTPSupport.HTTPRequest;
  901. params: DynamicWebpage.ParameterList; VAR statusMsg: XML.Content) : BOOLEAN;
  902. (* parameters "name", "info", "assistant", "date", "place", "maxpeople", "opentojoin" *)
  903. VAR name, info, assistant, date, place, maxpeople, opentojoin: Strings.String; group: Group;
  904. BEGIN (* obj # NIL *)
  905. IF (obj IS Group) THEN
  906. group := obj(Group);
  907. name := params.GetParameterValueByName("name");
  908. info := params.GetParameterValueByName("info");
  909. assistant := params.GetParameterValueByName("assistant");
  910. date := params.GetParameterValueByName("date");
  911. place := params.GetParameterValueByName("place");
  912. maxpeople := params.GetParameterValueByName("maxpeople");
  913. opentojoin := params.GetParameterValueByName("opentojoin");
  914. IF ((name # NIL) & (name^ # "")) THEN
  915. group.BeginModification;
  916. group.name := name; group.info := info; group.assistant := assistant; group.date := date; group.place := place;
  917. IF (maxpeople # NIL) THEN
  918. Strings.StrToInt(maxpeople^, group.maxPeople)
  919. ELSE
  920. group.maxPeople := 0
  921. END;
  922. IF ((opentojoin # NIL) & (opentojoin^ = "true")) THEN
  923. group.openToJoin := TRUE
  924. ELSE
  925. group.openToJoin := FALSE
  926. END;
  927. group.EndModification;
  928. RETURN TRUE
  929. ELSE
  930. statusMsg := WebStd.CreateXMLText("Name fehlt");
  931. RETURN FALSE
  932. END
  933. ELSE
  934. statusMsg := WebStd.CreateXMLText("object is not of type Group");
  935. RETURN FALSE
  936. END
  937. END UpdateObject;
  938. PROCEDURE ThisObjectName*() : Strings.String;
  939. BEGIN
  940. RETURN WebStd.GetString(AllGroupsDatagridName)
  941. END ThisObjectName;
  942. PROCEDURE ThisModuleName*() : Strings.String;
  943. BEGIN
  944. RETURN WebStd.GetString(ThisModuleNameStr)
  945. END ThisModuleName;
  946. (** abstract, returns the insert view for the initialization of a new web forum entry, without submit/back-input fields
  947. * and without hidden parameter for super entry in hierarchy.
  948. * superEntry is the parent web forum entry in a hierachical web forum, superEntry is NIL iff it is a root entry *)
  949. PROCEDURE GetInsertView*(superEntry: WebComplex.WebForumEntry; request: HTTPSupport.HTTPRequest): XML.Content;
  950. VAR table, tr, td, select, option: XML.Element;
  951. BEGIN
  952. NEW(table); table.SetName("table");
  953. WebComplex.AddTextFieldInputRow(table, "Name: ", "name", NIL);
  954. WebComplex.AddTextFieldInputRow(table, "Assistent: ", "assistant", NIL);
  955. WebComplex.AddTextFieldInputRow(table, "Zeit: ", "date", NIL);
  956. WebComplex.AddTextFieldInputRow(table, "Ort: ", "place", NIL);
  957. WebComplex.AddTextFieldInputRow(table, "Information: ", "info", NIL);
  958. WebComplex.AddTextFieldInputRow(table, "Maxmimale Platze: ", "maxpeople", NIL);
  959. NEW(tr); tr.SetName("tr"); table.AddContent(tr);
  960. NEW(td); td.SetName("td"); tr.AddContent(td);
  961. WebStd.AppendXMLContent(td, WebStd.CreateXMLText("Offen zum Einschreiben: "));
  962. NEW(td); td.SetName("td"); tr.AddContent(td);
  963. NEW(select); select.SetName("select"); td.AddContent(select);
  964. select.SetAttributeValue("name", "opentojoin");
  965. NEW(option); option.SetName("option"); select.AddContent(option);
  966. option.SetAttributeValue("value", "true");
  967. WebStd.AppendXMLContent(option, WebStd.CreateXMLText("Ja"));
  968. NEW(option); option.SetName("option"); select.AddContent(option);
  969. option.SetAttributeValue("value", "false");
  970. WebStd.AppendXMLContent(option, WebStd.CreateXMLText("Nein"));
  971. RETURN table
  972. END GetInsertView;
  973. PROCEDURE OnDetailViewActivated*(entryOid: LONGINT; request: HTTPSupport.HTTPRequest);
  974. BEGIN reInitializeSubContainer := TRUE (* the sub container has to showed in the default mode *)
  975. END OnDetailViewActivated;
  976. PROCEDURE GetTableHeader*(request: HTTPSupport.HTTPRequest): WebComplex.HeaderRow;
  977. VAR row: WebComplex.HeaderRow;
  978. BEGIN
  979. NEW(row, 8);
  980. row[0] := WebComplex.GetHeaderCellForText("Name", CompareName);
  981. row[1] := WebComplex.GetHeaderCellForText("Assistent", CompareAssistant);
  982. row[2] := WebComplex.GetHeaderCellForText("Zeit", CompareDate);
  983. row[3] := WebComplex.GetHeaderCellForText("Ort", ComparePlace);
  984. row[4] := WebComplex.GetHeaderCellForText("Information", CompareInfo);
  985. row[5] := WebComplex.GetHeaderCellForText("Freie Plaetze", CompareInfo);
  986. row[6] := WebComplex.GetHeaderCellForText(" ", NIL);
  987. row[7] := WebComplex.GetHeaderCellForText(" ", NIL);
  988. RETURN row
  989. END GetTableHeader;
  990. PROCEDURE GetEmptyListMessage*(request: HTTPSupport.HTTPRequest) : XML.Container;
  991. BEGIN
  992. RETURN WebStd.CreateXMLText(EmptyListText);
  993. END GetEmptyListMessage;
  994. PROCEDURE GetBackButtonLabel*(request: HTTPSupport.HTTPRequest) : Strings.String;
  995. BEGIN RETURN WebStd.GetString(BackButtonLabel)
  996. END GetBackButtonLabel;
  997. PROCEDURE GetInsertLinkLabel*(request: HTTPSupport.HTTPRequest) : Strings.String;
  998. BEGIN RETURN WebStd.GetString(InsertGroupText)
  999. END GetInsertLinkLabel;
  1000. PROCEDURE GetSubmitButtonLabel*(request: HTTPSupport.HTTPRequest): Strings.String;
  1001. BEGIN RETURN WebStd.GetString(SubmitButtonLabel)
  1002. END GetSubmitButtonLabel;
  1003. PROCEDURE GetUnapplySortLabel*(request: HTTPSupport.HTTPRequest): Strings.String;
  1004. BEGIN RETURN WebStd.GetString(UnapplySortLabel)
  1005. END GetUnapplySortLabel;
  1006. PROCEDURE GetUnapplyFilterLabel*(request: HTTPSupport.HTTPRequest): Strings.String;
  1007. BEGIN RETURN WebStd.GetString(UnapplyFilterLabel)
  1008. END GetUnapplyFilterLabel;
  1009. PROCEDURE GetSearchFilter*(text: Strings.String) : WebStd.PersistentDataFilter;
  1010. BEGIN
  1011. IF (text # NIL) THEN
  1012. NEW(searchText, Strings.Length(text^)+3);
  1013. Strings.Concat("*", text^, searchText^);
  1014. IF (Strings.Length(text^) > 0) THEN
  1015. Strings.Append(searchText^, "*");
  1016. Strings.LowerCase(searchText^)
  1017. END;
  1018. RETURN SearchFilter
  1019. END;
  1020. RETURN NIL
  1021. END GetSearchFilter;
  1022. PROCEDURE SearchFilter(obj: WebStd.PersistentDataObject) : BOOLEAN;
  1023. VAR entry: Group;
  1024. PROCEDURE Matches(VAR str: ARRAY OF CHAR) : BOOLEAN;
  1025. VAR lowStr: Strings.String;
  1026. BEGIN
  1027. lowStr := WebStd.GetString(str);
  1028. Strings.LowerCase(lowStr^);
  1029. RETURN Strings.Match(searchText^, lowStr^)
  1030. END Matches;
  1031. BEGIN (* searchText # NIL *)
  1032. IF (obj IS Group) THEN
  1033. entry := obj(Group);
  1034. IF ((entry.name # NIL) & (Matches(entry.name^))) THEN
  1035. RETURN TRUE
  1036. END;
  1037. IF ((entry.assistant # NIL) & (Matches(entry.assistant^))) THEN
  1038. RETURN TRUE
  1039. END;
  1040. IF ((entry.date # NIL) & (Matches(entry.date^))) THEN
  1041. RETURN TRUE
  1042. END;
  1043. IF ((entry.place # NIL) & (Matches(entry.place^))) THEN
  1044. RETURN TRUE
  1045. END;
  1046. IF ((entry.info # NIL) & (Matches(entry.info^))) THEN
  1047. RETURN TRUE
  1048. END
  1049. END;
  1050. RETURN FALSE
  1051. END SearchFilter;
  1052. PROCEDURE CompareName(obj1, obj2: WebStd.PersistentDataObject): BOOLEAN;
  1053. VAR f1, f2: Group;
  1054. BEGIN
  1055. IF ((obj1 IS Group) & (obj2 IS Group)) THEN
  1056. f1 := obj1(Group); f2 := obj2(Group);
  1057. IF (f2.name = NIL) THEN
  1058. RETURN FALSE
  1059. ELSIF (f1.name = NIL) THEN (* f2.name # NIL *)
  1060. RETURN TRUE
  1061. ELSE
  1062. RETURN f1.name^ < f2.name^
  1063. END
  1064. ELSE
  1065. RETURN FALSE
  1066. END
  1067. END CompareName;
  1068. PROCEDURE CompareAssistant(obj1, obj2: WebStd.PersistentDataObject): BOOLEAN;
  1069. VAR f1, f2: Group;
  1070. BEGIN
  1071. IF ((obj1 IS Group) & (obj2 IS Group)) THEN
  1072. f1 := obj1(Group); f2 := obj2(Group);
  1073. IF (f2.assistant = NIL) THEN
  1074. RETURN FALSE
  1075. ELSIF (f1.assistant = NIL) THEN (* f2.assistant # NIL *)
  1076. RETURN TRUE
  1077. ELSE
  1078. RETURN f1.assistant^ < f2.assistant^
  1079. END
  1080. ELSE
  1081. RETURN FALSE
  1082. END
  1083. END CompareAssistant;
  1084. PROCEDURE CompareDate(obj1, obj2: WebStd.PersistentDataObject): BOOLEAN;
  1085. VAR f1, f2: Group;
  1086. BEGIN
  1087. IF ((obj1 IS Group) & (obj2 IS Group)) THEN
  1088. f1 := obj1(Group); f2 := obj2(Group);
  1089. IF (f2.date = NIL) THEN
  1090. RETURN FALSE
  1091. ELSIF (f1.date = NIL) THEN (* f2.date # NIL *)
  1092. RETURN TRUE
  1093. ELSE
  1094. RETURN f1.date^ < f2.date^
  1095. END
  1096. ELSE
  1097. RETURN FALSE
  1098. END
  1099. END CompareDate;
  1100. PROCEDURE ComparePlace(obj1, obj2: WebStd.PersistentDataObject): BOOLEAN;
  1101. VAR f1, f2: Group;
  1102. BEGIN
  1103. IF ((obj1 IS Group) & (obj2 IS Group)) THEN
  1104. f1 := obj1(Group); f2 := obj2(Group);
  1105. IF (f2.place = NIL) THEN
  1106. RETURN FALSE
  1107. ELSIF (f1.place = NIL) THEN (* f2.place # NIL *)
  1108. RETURN TRUE
  1109. ELSE
  1110. RETURN f1.place^ < f2.place^
  1111. END
  1112. ELSE
  1113. RETURN FALSE
  1114. END
  1115. END ComparePlace;
  1116. PROCEDURE CompareInfo(obj1, obj2: WebStd.PersistentDataObject): BOOLEAN;
  1117. VAR f1, f2: Group;
  1118. BEGIN
  1119. IF ((obj1 IS Group) & (obj2 IS Group)) THEN
  1120. f1 := obj1(Group); f2 := obj2(Group);
  1121. IF (f2.info = NIL) THEN
  1122. RETURN FALSE
  1123. ELSIF (f1.info = NIL) THEN (* f2.info # NIL *)
  1124. RETURN TRUE
  1125. ELSE
  1126. RETURN f1.info^ < f2.info^
  1127. END
  1128. ELSE
  1129. RETURN FALSE
  1130. END
  1131. END CompareInfo;
  1132. END AllGroupsDatagrid;
  1133. (** statefull exercise grades edit list for a group
  1134. * <ExerciseGroups:GradesEditList id="MyGradesEditList3" groupoid=".." prevalencesystem=".."/>
  1135. *)
  1136. GradesEditList* = OBJECT(DynamicWebpage.StateFullActiveElement);
  1137. VAR
  1138. group: Group;
  1139. PROCEDURE &Init*;
  1140. BEGIN group := NIL
  1141. END Init;
  1142. PROCEDURE Transform*(input: XML.Element; request: HTTPSupport.HTTPRequest) : XML.Content;
  1143. VAR groupOid: LONGINT; groupOidStr, prevSysName: Strings.String; persObj: PrevalenceSystem.PersistentObject;
  1144. prevSys: PrevalenceSystem.PrevalenceSystem;
  1145. BEGIN
  1146. groupOidStr := input.GetAttributeValue("groupoid");
  1147. prevSysName := input.GetAttributeValue("prevalencesystem");
  1148. (* get the prevalence system *)
  1149. IF (prevSysName # NIL) THEN
  1150. prevSys := PrevalenceSystem.GetPrevalenceSystem(prevSysName^)
  1151. ELSE
  1152. prevSys := PrevalenceSystem.standardPrevalenceSystem
  1153. END;
  1154. IF ((groupOidStr # NIL) & (prevSys # NIL)) THEN
  1155. Strings.StrToInt(groupOidStr^, groupOid);
  1156. persObj := prevSys.GetPersistentObject(groupOid);
  1157. IF ((persObj # NIL) & (persObj IS Group)) THEN
  1158. group := persObj(Group);
  1159. RETURN TransformForGroup(input, request)
  1160. ELSE
  1161. RETURN WebStd.CreateXMLText("ExerciseGroups:GradesEditList - The specified 'groupoid' does not refer to a valid group")
  1162. END
  1163. ELSE
  1164. RETURN WebStd.CreateXMLText("ExerciseGroups:GradesEditList - need attribute 'groupoid' and a name of a valid prevalence system");
  1165. END
  1166. END Transform;
  1167. PROCEDURE TransformForGroup(input: XML.Element; request: HTTPSupport.HTTPRequest) : XML.Content;
  1168. VAR container: XML.Container; objectId: Strings.String; formular, htmlInput, pTag, label, eventLink: XML.Element;
  1169. BEGIN (* group # NIL *)
  1170. objectId := input.GetAttributeValue(DynamicWebpage.XMLAttributeObjectIdName); (* objectId # NIL *)
  1171. NEW(container);
  1172. NEW(pTag); pTag.SetName("p"); container.AddContent(pTag);
  1173. NEW(eventLink); eventLink.SetName("WebStd:EventLink");
  1174. eventLink.SetAttributeValue("xmlns:WebStd", "WebStd");
  1175. NEW(label); label.SetName("Label"); pTag.AddContent(eventLink);
  1176. WebStd.AppendXMLContent(label, WebStd.CreateXMLText(AddNewExerciseLabel));
  1177. eventLink.AddContent(label);
  1178. eventLink.SetAttributeValue("method", "AddNewExercise");
  1179. eventLink.SetAttributeValue("object", "GradesEditList");
  1180. eventLink.SetAttributeValue("module", ThisModuleNameStr);
  1181. eventLink.SetAttributeValue("objectid", objectId^);
  1182. NEW(formular); formular.SetName("WebStd:Formular"); container.AddContent(formular);
  1183. formular.SetAttributeValue("xmlns:WebStd", "WebStd");
  1184. formular.SetAttributeValue("method", "UpdateList");
  1185. formular.SetAttributeValue("object", "GradesEditList");
  1186. formular.SetAttributeValue("module", ThisModuleNameStr);
  1187. formular.SetAttributeValue("objectid", objectId^);
  1188. WebStd.AppendXMLContent(formular, GetGradesEditView(objectId, CompareLastName));
  1189. NEW(htmlInput); htmlInput.SetName("input"); formular.AddContent(htmlInput);
  1190. htmlInput.SetAttributeValue("type", "submit");
  1191. htmlInput.SetAttributeValue("name", "submitbutton");
  1192. htmlInput.SetAttributeValue("value", SubmitButtonLabel);
  1193. RETURN container
  1194. END TransformForGroup;
  1195. (* get the edit view for all grades of all exercise group members *)
  1196. PROCEDURE GetGradesEditView(objectId: Strings.String; activeOrdering: WebStd.PersistentDataCompare) : XML.Content;
  1197. VAR table: XML.Element; list: WebStd.PersistentDataObjectList; i, k, nofCols: LONGINT; person: Person;
  1198. BEGIN (* group # NIL *)
  1199. IF (group.members # NIL) THEN
  1200. nofCols := 0;
  1201. list := group.members.GetElementList(WebStd.DefaultPersistentDataFilter, activeOrdering);
  1202. IF (list # NIL) THEN
  1203. (* first determine the maximum number of columns *)
  1204. FOR i := 0 TO LEN(list)-1 DO (* list[i] # NIL *)
  1205. IF (list[i] IS Person) THEN
  1206. person := list[i](Person);
  1207. IF (person.grades # NIL) THEN
  1208. person.grades.Lock; k := person.grades.GetCount(); person.grades.Unlock
  1209. END;
  1210. IF (k > nofCols) THEN nofCols := k END
  1211. END
  1212. END;
  1213. IF (nofCols > 0) THEN
  1214. NEW(table); table.SetName("table");
  1215. table.AddContent(GetExerciseListHeaderRow(objectId, TRUE, nofCols));
  1216. FOR i := 0 TO LEN(list)-1 DO
  1217. IF (list[i] IS Person) THEN
  1218. person := list[i](Person);
  1219. table.AddContent(GetPersonGradesEditRow(nofCols, person))
  1220. END
  1221. END;
  1222. RETURN table
  1223. END
  1224. END
  1225. END;
  1226. RETURN NIL
  1227. END GetGradesEditView;
  1228. (* get XHTML table header row for the exercise grade list. If 'allowDelete' is true then the exercise can be deleted *)
  1229. PROCEDURE GetExerciseListHeaderRow(objectId: Strings.String; allowDelete: BOOLEAN;
  1230. nofCols: LONGINT) : XML.Element;
  1231. VAR tr, td, eventLink, eventParam, label, br: XML.Element; i: LONGINT; iStr: ARRAY 14 OF CHAR;
  1232. str: Strings.String;
  1233. BEGIN
  1234. IF(nofCols > 0) THEN
  1235. NEW(tr); tr.SetName("tr");
  1236. NEW(td); td.SetName("td"); tr.AddContent(td);
  1237. WebStd.AppendXMLContent(td, WebStd.CreateXMLText("Last name"));
  1238. NEW(td); td.SetName("td"); tr.AddContent(td);
  1239. WebStd.AppendXMLContent(td, WebStd.CreateXMLText("First name"));
  1240. FOR i := 0 TO nofCols-1 DO
  1241. NEW(td); td.SetName("td"); tr.AddContent(td);
  1242. Strings.IntToStr(i+1, iStr);
  1243. NEW(str, Strings.Length(ExerciseName)+LEN(iStr)+1);
  1244. COPY(ExerciseName, str^); Strings.Append(str^, iStr);
  1245. WebStd.AppendXMLContent(td, WebStd.CreateXMLText(str^));
  1246. IF (allowDelete) THEN
  1247. NEW(br); br.SetName("br"); td.AddContent(br);
  1248. NEW(eventLink); eventLink.SetName("WebStd:EventLink"); td.AddContent(eventLink);
  1249. eventLink.SetAttributeValue("xmlns:WebStd", "WebStd");
  1250. NEW(label); label.SetName("Label");
  1251. WebStd.AppendXMLContent(label, WebStd.CreateXMLText(DeleteAnExerciseLabel));
  1252. eventLink.AddContent(label);
  1253. eventLink.SetAttributeValue("method", "DeleteExercise");
  1254. eventLink.SetAttributeValue("object", "GradesEditList");
  1255. eventLink.SetAttributeValue("module", ThisModuleNameStr);
  1256. eventLink.SetAttributeValue("objectid", objectId^);
  1257. NEW(eventParam); eventParam.SetName("Param");
  1258. eventParam.SetAttributeValue("name", "exerciseno");
  1259. Strings.IntToStr(i, iStr);
  1260. eventParam.SetAttributeValue("value", iStr);
  1261. eventLink.AddContent(eventParam);
  1262. END
  1263. END;
  1264. NEW(td); td.SetName("td"); tr.AddContent(td);
  1265. WebStd.AppendXMLContent(td, WebStd.CreateXMLText(" "))
  1266. ELSE
  1267. tr := NIL
  1268. END;
  1269. RETURN tr
  1270. END GetExerciseListHeaderRow;
  1271. (* get a edit view row for a persons exercise grades, if the person has not nofCols exercise grades then insert new ones *)
  1272. PROCEDURE GetPersonGradesEditRow(nofCols: LONGINT; person: Person) : XML.Element;
  1273. VAR tr, td: XML.Element; number, i: LONGINT;
  1274. PROCEDURE GetInputName(oid, exerciseNo: LONGINT) : Strings.String;
  1275. VAR nameStr: Strings.String; oidStr, exerciseNoStr: ARRAY 14 OF CHAR;
  1276. BEGIN
  1277. Strings.IntToStr(oid, oidStr); Strings.IntToStr(exerciseNo, exerciseNoStr);
  1278. NEW(nameStr, Strings.Length(PersonGradePrefixName)+2*14+1);
  1279. Strings.Concat(PersonGradePrefixName, oidStr, nameStr^);
  1280. Strings.Append(nameStr^, "-"); Strings.Append(nameStr^, exerciseNoStr);
  1281. RETURN nameStr
  1282. END GetInputName;
  1283. PROCEDURE GetInputField(exerciseNo, grade: LONGINT) : XML.Element;
  1284. VAR td, input: XML.Element; numberStr: ARRAY 14 OF CHAR; name: Strings.String;
  1285. BEGIN
  1286. Strings.IntToStr(grade, numberStr);
  1287. name := GetInputName(person.oid, exerciseNo); (* name # NIL *)
  1288. NEW(td); td.SetName("td");
  1289. NEW(input); input.SetName("input"); td.AddContent(input);
  1290. input.SetAttributeValue("type", "text");
  1291. input.SetAttributeValue("size", "2");
  1292. input.SetAttributeValue("name", name^);
  1293. input.SetAttributeValue("value", numberStr);
  1294. RETURN td
  1295. END GetInputField;
  1296. BEGIN
  1297. IF ((person# NIL) & (person.grades # NIL) & (nofCols > 0)) THEN
  1298. person.grades.Lock;
  1299. NEW(tr); tr.SetName("tr");
  1300. NEW(td); td.SetName("td"); tr.AddContent(td);
  1301. IF (person.lastname # NIL) THEN
  1302. WebStd.AppendXMLContent(td, WebStd.CreateXMLText(person.lastname^))
  1303. ELSE
  1304. WebStd.AppendXMLContent(td, WebStd.CreateXMLText(" "))
  1305. END;
  1306. NEW(td); td.SetName("td"); tr.AddContent(td);
  1307. IF (person.firstname # NIL) THEN
  1308. WebStd.AppendXMLContent(td, WebStd.CreateXMLText(person.firstname^))
  1309. ELSE
  1310. WebStd.AppendXMLContent(td, WebStd.CreateXMLText(" "))
  1311. END;
  1312. FOR i := 0 TO MIN(person.grades.GetCount(), nofCols)-1 DO
  1313. number := person.grades.GetItem(i);
  1314. tr.AddContent(GetInputField(i, number))
  1315. END;
  1316. person.grades.Unlock;
  1317. IF (i < nofCols) THEN
  1318. person.BeginModification;
  1319. WHILE (i < nofCols) DO
  1320. person.grades.Add(0);
  1321. tr.AddContent(GetInputField(i, 0));
  1322. INC(i)
  1323. END;
  1324. person.EndModification
  1325. END;
  1326. NEW(td); td.SetName("td"); tr.AddContent(td);
  1327. WebStd.AppendXMLContent(td, GetNotification(person))
  1328. END;
  1329. RETURN tr
  1330. END GetPersonGradesEditRow;
  1331. PROCEDURE GetNotification(person: Person) : XML.Content;
  1332. VAR aTag: XML.Element; dynStr: DynamicStrings.DynamicString; i, number: LONGINT;
  1333. numberStr, iStr: ARRAY 14 OF CHAR; str: Strings.String;
  1334. PROCEDURE Append(text: ARRAY OF CHAR);
  1335. VAR str: Strings.String;
  1336. BEGIN str := WebStd.GetString(text); dynStr.Append(str^)
  1337. END Append;
  1338. BEGIN (* person # NIL *)
  1339. IF ((person.grades # NIL) & (person.grades.GetCount() > 0) & (person.email # NIL) & (person.email^ # "")) THEN
  1340. NEW(aTag); aTag.SetName("a");
  1341. NEW(dynStr); Append("mailto:");
  1342. dynStr.Append(person.email^);
  1343. Append("?subject=");
  1344. IF ((group # NIL) & (group.name # NIL)) THEN
  1345. dynStr.Append(group.name^)
  1346. END;
  1347. Append(" - "); Append(GradeNotificationSubject);
  1348. Append("&body="); Append(GradeNotificationSalutation); Append(" ");
  1349. IF (person.firstname # NIL) THEN
  1350. dynStr.Append(person.firstname^)
  1351. END;
  1352. Append(","); Append(MailCR); Append(MailCR);
  1353. Append(GradeNotificationBodyHead); Append(MailCR);
  1354. person.grades.Lock;
  1355. FOR i := 0 TO person.grades.GetCount()-1 DO
  1356. Strings.IntToStr(i+1, iStr);
  1357. number := person.grades.GetItem(i); Strings.IntToStr(number, numberStr);
  1358. Append(ExerciseName); Append(" "); dynStr.Append(iStr); Append(": "); dynStr.Append(numberStr);
  1359. Append(MailCR)
  1360. END;
  1361. person.grades.Unlock;
  1362. Append(MailCR); Append(GradeNotificationBodyTail); Append(MailCR); Append(MailCR);
  1363. IF (group.assistant # NIL) THEN
  1364. dynStr.Append(group.assistant^); Append(MailCR)
  1365. END;
  1366. str := dynStr.ToArrOfChar();
  1367. str := WebStd.GetEncXMLAttributeText(str^);
  1368. aTag.SetAttributeValue("href", str^);
  1369. WebStd.AppendXMLContent(aTag, WebStd.CreateXMLText(SendGradeNotoficationLabel));
  1370. RETURN aTag
  1371. ELSE
  1372. RETURN WebStd.CreateXMLText(" ")
  1373. END
  1374. END GetNotification;
  1375. PROCEDURE UpdateList(request: HTTPSupport.HTTPRequest; params: DynamicWebpage.ParameterList);
  1376. VAR tempStr, personOidStr, exerciseNoStr: Strings.String;
  1377. i, length, sepIdx, personOid, exerciseNo, newGrade: LONGINT; par: DynamicWebpage.Parameter;
  1378. (* params: the grades for all group members *)
  1379. BEGIN
  1380. (* if this event handler is manually invoked on this active element such that the active element was not previously
  1381. * processed then group=NIL and no changes are made. This guarantees that no unauthorized user can edit the grades *)
  1382. IF ((group # NIL) & (params.parameters # NIL)) THEN
  1383. FOR i := 0 TO LEN(params.parameters)-1 DO
  1384. par := params.parameters[i];
  1385. IF ((par # NIL) & (par.name # NIL) & (par.value # NIL)) THEN
  1386. IF (Strings.Pos(PersonGradePrefixName, par.name^) = 0) THEN
  1387. tempStr := WebStd.GetString(par.name^);
  1388. Strings.Delete(tempStr^, 0, Strings.Length(PersonGradePrefixName));
  1389. sepIdx := Strings.Pos("-", tempStr^);
  1390. length := Strings.Length(tempStr^);
  1391. IF ((sepIdx > 0) & (sepIdx < length-1)) THEN
  1392. NEW(personOidStr, sepIdx+1); Strings.Copy(tempStr^, 0, sepIdx, personOidStr^);
  1393. NEW(exerciseNoStr, length-sepIdx); Strings.Copy(tempStr^, sepIdx+1, length-sepIdx-1, exerciseNoStr^);
  1394. Strings.StrToInt(personOidStr^, personOid); Strings.StrToInt(exerciseNoStr^, exerciseNo);
  1395. Strings.StrToInt(par.value^, newGrade);
  1396. group.UpdateGrade(personOid, exerciseNo, newGrade)
  1397. END
  1398. END
  1399. END
  1400. END
  1401. END
  1402. END UpdateList;
  1403. PROCEDURE AddNewExercise(request: HTTPSupport.HTTPRequest; params: DynamicWebpage.ParameterList);
  1404. BEGIN
  1405. IF (group # NIL) THEN
  1406. group.AddNewExercise
  1407. END
  1408. END AddNewExercise;
  1409. PROCEDURE DeleteExercise(request: HTTPSupport.HTTPRequest; params: DynamicWebpage.ParameterList);
  1410. VAR exerciseNoStr: Strings.String; exerciseNo: LONGINT;
  1411. (* parameters: "exerciseno" *)
  1412. BEGIN
  1413. exerciseNoStr := params.GetParameterValueByName("exerciseno");
  1414. IF (exerciseNoStr # NIL) THEN
  1415. Strings.StrToInt(exerciseNoStr^, exerciseNo);
  1416. IF (group # NIL) THEN
  1417. group.DeleteExercise(exerciseNo)
  1418. END
  1419. ELSE
  1420. KernelLog.String("ExerciseGroups:GradesEditList - event handler 'DeleteExercise' has parameter 'exerciseno'.");
  1421. KernelLog.Ln
  1422. END
  1423. END DeleteExercise;
  1424. PROCEDURE GetEventHandlers*() : DynamicWebpage.EventHandlerList;
  1425. VAR list: DynamicWebpage.EventHandlerList;
  1426. BEGIN
  1427. NEW(list, 3);
  1428. NEW(list[0], "UpdateList", UpdateList);
  1429. NEW(list[1], "AddNewExercise", AddNewExercise);
  1430. NEW(list[2], "DeleteExercise", DeleteExercise);
  1431. RETURN list
  1432. END GetEventHandlers;
  1433. END GradesEditList;
  1434. (** stateless summary list for all groups of one lecture
  1435. * <ExerciseGroups:SummaryList containername=".." prevalencesystem=".."/>
  1436. *)
  1437. SummaryList* = OBJECT(DynamicWebpage.StateLessActiveElement);
  1438. PROCEDURE Transform*(input: XML.Element; request: HTTPSupport.HTTPRequest) : XML.Content;
  1439. VAR containerName, prevSysName: Strings.String; persCont: WebStd.PersistentDataContainer;
  1440. persList: WebStd.PersistentDataObjectList; i: LONGINT; outputCont: XML.Container;
  1441. entry: WebComplex.WebForumEntry; prevSys: PrevalenceSystem.PrevalenceSystem;
  1442. BEGIN
  1443. containerName := input.GetAttributeValue("containername");
  1444. prevSysName := input.GetAttributeValue("prevalencesystem");
  1445. (* get the prevalence system *)
  1446. IF (prevSysName # NIL) THEN
  1447. prevSys := PrevalenceSystem.GetPrevalenceSystem(prevSysName^)
  1448. ELSE
  1449. prevSys := PrevalenceSystem.standardPrevalenceSystem
  1450. END;
  1451. IF ((containerName # NIL) & (prevSys # NIL)) THEN
  1452. persCont := WebStd.GetPersistentDataContainer(prevSys, containerName^);
  1453. IF (persCont # NIL) THEN
  1454. persList := persCont.GetElementList(NIL, NIL);
  1455. IF ((persList # NIL) & (LEN(persList) > 0)) THEN
  1456. NEW(outputCont);
  1457. FOR i := 0 TO LEN(persList)-1 DO
  1458. IF (persList[i] IS WebComplex.WebForumEntry) THEN (* persList[i] # NIL *)
  1459. entry := persList[i](WebComplex.WebForumEntry);
  1460. WebStd.AppendXMLContent(outputCont, entry.DetailView(NIL, request))
  1461. END
  1462. END;
  1463. RETURN outputCont
  1464. END
  1465. END
  1466. END;
  1467. RETURN NIL
  1468. END Transform;
  1469. END SummaryList;
  1470. VAR
  1471. personDesc: PrevalenceSystem.PersistentObjectDescriptor; (* descriptor for Person *)
  1472. groupDesc: PrevalenceSystem.PersistentObjectDescriptor; (* descriptor for Group *)
  1473. (* returns TRUE iff request is an authorized user or an administrator *)
  1474. PROCEDURE IsAuthorizedUser(request: HTTPSupport.HTTPRequest) : BOOLEAN;
  1475. VAR session: HTTPSession.Session;
  1476. BEGIN
  1477. session := HTTPSession.GetSession(request); (* session # NIL *)
  1478. RETURN ((WebAccounts.GetAuthWebAccountForSession(session) # NIL) OR
  1479. WebAccounts.IsSessionAuthorizedAsAdmin(session))
  1480. END IsAuthorizedUser;
  1481. PROCEDURE CompareLastName(obj1, obj2: WebStd.PersistentDataObject): BOOLEAN;
  1482. VAR f1, f2: Person;
  1483. BEGIN
  1484. IF ((obj1 IS Person) & (obj2 IS Person)) THEN
  1485. f1 := obj1(Person); f2 := obj2(Person);
  1486. IF (f2.lastname = NIL) THEN
  1487. RETURN FALSE
  1488. ELSIF (f1.lastname = NIL) THEN (* f2.lastname # NIL *)
  1489. RETURN TRUE
  1490. ELSE
  1491. RETURN f1.lastname^ < f2.lastname^
  1492. END
  1493. ELSE
  1494. RETURN FALSE
  1495. END
  1496. END CompareLastName;
  1497. PROCEDURE GetNewPerson() : PrevalenceSystem.PersistentObject;
  1498. VAR obj: Person;
  1499. BEGIN NEW(obj); RETURN obj
  1500. END GetNewPerson;
  1501. PROCEDURE GetNewGroup() : PrevalenceSystem.PersistentObject;
  1502. VAR obj: Group;
  1503. BEGIN NEW(obj); RETURN obj
  1504. END GetNewGroup;
  1505. (** used by the prevalence system *)
  1506. PROCEDURE GetPersistentObjectDescriptors*() : PrevalenceSystem.PersistentObjectDescSet;
  1507. VAR descSet : PrevalenceSystem.PersistentObjectDescSet;
  1508. descs: ARRAY 2 OF PrevalenceSystem.PersistentObjectDescriptor;
  1509. BEGIN
  1510. descs[0] := personDesc;
  1511. descs[1] := groupDesc;
  1512. NEW(descSet, descs);
  1513. RETURN descSet
  1514. END GetPersistentObjectDescriptors;
  1515. PROCEDURE CreateSingleGroupDgElement() : DynamicWebpage.ActiveElement;
  1516. VAR obj: SingleGroupDatagrid;
  1517. BEGIN
  1518. NEW(obj); RETURN obj
  1519. END CreateSingleGroupDgElement;
  1520. PROCEDURE CreateAllGroupsDatagridElement() : DynamicWebpage.ActiveElement;
  1521. VAR obj: AllGroupsDatagrid;
  1522. BEGIN
  1523. NEW(obj); RETURN obj
  1524. END CreateAllGroupsDatagridElement;
  1525. PROCEDURE CreateGradesEditListElement() : DynamicWebpage.ActiveElement;
  1526. VAR obj: GradesEditList;
  1527. BEGIN
  1528. NEW(obj); RETURN obj
  1529. END CreateGradesEditListElement;
  1530. PROCEDURE CreateSummaryListElement() : DynamicWebpage.ActiveElement;
  1531. VAR obj: SummaryList;
  1532. BEGIN
  1533. NEW(obj); RETURN obj
  1534. END CreateSummaryListElement;
  1535. PROCEDURE GetActiveElementDescriptors*() : DynamicWebpage.ActiveElementDescSet;
  1536. VAR desc: POINTER TO ARRAY OF DynamicWebpage.ActiveElementDescriptor;
  1537. descSet: DynamicWebpage.ActiveElementDescSet;
  1538. BEGIN
  1539. NEW(desc, 4);
  1540. NEW(desc[0], "SingleGroupDatagrid", CreateSingleGroupDgElement);
  1541. NEW(desc[1], "AllGroupsDatagrid", CreateAllGroupsDatagridElement);
  1542. NEW(desc[2], "GradesEditList", CreateGradesEditListElement);
  1543. NEW(desc[3], "SummaryList", CreateSummaryListElement);
  1544. NEW(descSet, desc^); RETURN descSet
  1545. END GetActiveElementDescriptors;
  1546. BEGIN
  1547. NEW(personDesc, ThisModuleNameStr, "Person", GetNewPerson);
  1548. NEW(groupDesc, ThisModuleNameStr, "Group", GetNewGroup)
  1549. END ExerciseGroups.