import_csv.php 120 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054
  1. <?php
  2. /* For licensing terms, see /license.txt */
  3. use Chamilo\CourseBundle\Entity\CCalendarEvent;
  4. use Chamilo\CourseBundle\Entity\CItemProperty;
  5. use Chamilo\PluginBundle\Entity\StudentFollowUp\CarePost;
  6. use Fhaculty\Graph\Graph;
  7. use Graphp\GraphViz\GraphViz;
  8. use Monolog\Handler\BufferHandler;
  9. use Monolog\Handler\NativeMailerHandler;
  10. use Monolog\Handler\RotatingFileHandler;
  11. use Monolog\Handler\StreamHandler;
  12. use Monolog\Logger;
  13. if (PHP_SAPI != 'cli') {
  14. die('Run this script through the command line or comment this line in the code');
  15. }
  16. if (file_exists('multiple_url_fix.php')) {
  17. require 'multiple_url_fix.php';
  18. }
  19. require_once __DIR__.'/../inc/global.inc.php';
  20. ini_set('memory_limit', -1);
  21. ini_set('max_execution_time', 0);
  22. ini_set('log_errors', '1');
  23. ini_set('display_errors', '1');
  24. /**
  25. * Class ImportCsv.
  26. */
  27. class ImportCsv
  28. {
  29. public $test;
  30. public $defaultLanguage = 'dutch';
  31. public $extraFieldIdNameList = [
  32. 'session' => 'external_session_id',
  33. 'session_career' => 'external_career_id',
  34. 'course' => 'external_course_id',
  35. 'user' => 'external_user_id',
  36. 'calendar_event' => 'external_calendar_event_id',
  37. 'career' => 'external_career_id',
  38. 'career_urls' => 'career_urls',
  39. 'career_diagram' => 'career_diagram',
  40. ];
  41. public $defaultAdminId = 1;
  42. public $defaultSessionVisibility = 1;
  43. /**
  44. * When creating a user the expiration date is set to registration date + this value.
  45. *
  46. * @var int number of years
  47. */
  48. public $expirationDateInUserCreation = 1;
  49. public $batchSize = 20;
  50. /**
  51. * When updating a user the expiration date is set to update date + this value.
  52. *
  53. * @var int number of years
  54. */
  55. public $expirationDateInUserUpdate = 1;
  56. public $daysCoachAccessBeforeBeginning = 14;
  57. public $daysCoachAccessAfterBeginning = 14;
  58. public $conditions;
  59. private $logger;
  60. private $dumpValues;
  61. private $updateEmailToDummy;
  62. /**
  63. * @param Monolog\Logger $logger
  64. * @param array
  65. */
  66. public function __construct($logger, $conditions)
  67. {
  68. $this->logger = $logger;
  69. $this->conditions = $conditions;
  70. $this->updateEmailToDummy = false;
  71. }
  72. /**
  73. * @param bool $dump
  74. */
  75. public function setDumpValues($dump)
  76. {
  77. $this->dumpValues = $dump;
  78. }
  79. /**
  80. * @return bool
  81. */
  82. public function getDumpValues()
  83. {
  84. return $this->dumpValues;
  85. }
  86. /**
  87. * Runs the import process.
  88. */
  89. public function run()
  90. {
  91. global $_configuration;
  92. $value = api_get_configuration_value('import_csv_custom_url_id');
  93. if (!empty($value)) {
  94. $_configuration['access_url'] = $value;
  95. }
  96. $path = api_get_path(SYS_CODE_PATH).'cron/incoming/';
  97. if (!is_dir($path)) {
  98. echo "The folder! $path does not exits";
  99. return 0;
  100. }
  101. if ($this->getDumpValues()) {
  102. $this->dumpDatabaseTables();
  103. }
  104. echo "Reading files: ".PHP_EOL.PHP_EOL;
  105. $files = scandir($path);
  106. $fileToProcess = [];
  107. $fileToProcessStatic = [];
  108. $teacherBackup = [];
  109. $groupBackup = [];
  110. $this->prepareImport();
  111. if (!empty($files)) {
  112. foreach ($files as $file) {
  113. $fileInfo = pathinfo($file);
  114. if (isset($fileInfo['extension']) && $fileInfo['extension'] === 'csv') {
  115. // Checking teachers_yyyymmdd.csv,
  116. // courses_yyyymmdd.csv, students_yyyymmdd.csv and sessions_yyyymmdd.csv
  117. $parts = explode('_', $fileInfo['filename']);
  118. $preMethod = ucwords($parts[1]);
  119. $preMethod = str_replace('-static', 'Static', $preMethod);
  120. $method = 'import'.$preMethod;
  121. $isStatic = strpos($method, 'Static');
  122. if ($method == 'importSessionsextidStatic') {
  123. $method = 'importSessionsExtIdStatic';
  124. }
  125. if ($method == 'importCourseinsertStatic') {
  126. $method = 'importSubscribeUserToCourse';
  127. }
  128. if ($method == 'importUnsubsessionsextidStatic') {
  129. $method = 'importUnsubsessionsExtidStatic';
  130. }
  131. if ($method == 'importCareersdiagram') {
  132. $method = 'importCareersDiagram';
  133. }
  134. if ($method == 'importOpensessions') {
  135. $method = 'importOpenSessions';
  136. }
  137. if ($method == 'importSubsessionsextidStatic') {
  138. $method = 'importSubscribeUserToCourseSessionExtStatic';
  139. }
  140. if (method_exists($this, $method)) {
  141. if ((
  142. $method == 'importSubscribeStatic' ||
  143. $method == 'importSubscribeUserToCourse'
  144. ) ||
  145. empty($isStatic)
  146. ) {
  147. $fileToProcess[$parts[1]][] = [
  148. 'method' => $method,
  149. 'file' => $path.$fileInfo['basename'],
  150. ];
  151. } else {
  152. $fileToProcessStatic[$parts[1]][] = [
  153. 'method' => $method,
  154. 'file' => $path.$fileInfo['basename'],
  155. ];
  156. }
  157. } else {
  158. echo "Error - This file '$file' can't be processed.".PHP_EOL;
  159. echo "Trying to call $method".PHP_EOL;
  160. echo "The file have to has this format:".PHP_EOL;
  161. echo "prefix_students_ddmmyyyy.csv, prefix_teachers_ddmmyyyy.csv,
  162. prefix_courses_ddmmyyyy.csv, prefix_sessions_ddmmyyyy.csv ".PHP_EOL;
  163. exit;
  164. }
  165. }
  166. }
  167. if (empty($fileToProcess) && empty($fileToProcessStatic)) {
  168. echo 'Error - no files to process.';
  169. return 0;
  170. }
  171. $sections = [
  172. 'students',
  173. 'teachers',
  174. 'courses',
  175. 'sessions',
  176. 'opensessions',
  177. 'subscribe-static',
  178. 'courseinsert-static',
  179. 'unsubscribe-static',
  180. 'care',
  181. 'careers',
  182. 'careersdiagram',
  183. ];
  184. foreach ($sections as $section) {
  185. if (isset($fileToProcess[$section]) && !empty($fileToProcess[$section])) {
  186. $this->logger->addInfo("-- Import $section --");
  187. $files = $fileToProcess[$section];
  188. foreach ($files as $fileInfo) {
  189. $method = $fileInfo['method'];
  190. $file = $fileInfo['file'];
  191. echo 'File: '.$file.PHP_EOL;
  192. echo 'Method : '.$method.PHP_EOL;
  193. echo PHP_EOL;
  194. $this->logger->addInfo("Reading file: $file");
  195. $this->logger->addInfo("Loading method $method ");
  196. if ($method == 'importSessions' || $method == 'importOpenSessions') {
  197. $this->$method(
  198. $file,
  199. true,
  200. $teacherBackup,
  201. $groupBackup
  202. );
  203. } else {
  204. $this->$method($file, true);
  205. }
  206. $this->logger->addInfo("--Finish reading file--");
  207. }
  208. }
  209. }
  210. $sections = [
  211. 'students-static',
  212. 'teachers-static',
  213. 'courses-static',
  214. 'sessions-static',
  215. 'sessionsextid-static',
  216. 'unsubscribe-static',
  217. 'unsubsessionsextid-static',
  218. 'subsessionsextid-static',
  219. 'calendar-static',
  220. ];
  221. foreach ($sections as $section) {
  222. if (isset($fileToProcessStatic[$section]) &&
  223. !empty($fileToProcessStatic[$section])
  224. ) {
  225. $this->logger->addInfo("-- Import static files $section --");
  226. $files = $fileToProcessStatic[$section];
  227. foreach ($files as $fileInfo) {
  228. $method = $fileInfo['method'];
  229. $file = $fileInfo['file'];
  230. echo 'Static file: '.$file.PHP_EOL;
  231. echo 'Method : '.$method.PHP_EOL;
  232. echo PHP_EOL;
  233. $this->logger->addInfo("Reading static file: $file");
  234. $this->logger->addInfo("Loading method $method ");
  235. $this->$method(
  236. $file,
  237. true,
  238. $teacherBackup,
  239. $groupBackup
  240. );
  241. $this->logger->addInfo("--Finish reading file--");
  242. }
  243. }
  244. }
  245. $this->logger->addInfo("teacher backup");
  246. $this->logger->addInfo(print_r($teacherBackup, 1));
  247. }
  248. }
  249. /**
  250. * @param $file
  251. * @param bool $moveFile
  252. */
  253. public function importCare($file, $moveFile = false)
  254. {
  255. $data = Import::csv_reader($file);
  256. $counter = 1;
  257. $batchSize = $this->batchSize;
  258. $em = Database::getManager();
  259. if (!empty($data)) {
  260. $this->logger->addInfo(count($data)." records found.");
  261. $items = [];
  262. foreach ($data as $list) {
  263. $post = [];
  264. foreach ($list as $key => $value) {
  265. $key = (string) trim($key);
  266. // Remove utf8 bom
  267. $key = preg_replace('/[\x00-\x1F\x80-\xFF]/', '', $key);
  268. $post[$key] = $value;
  269. }
  270. if (empty($post)) {
  271. continue;
  272. }
  273. $externalId = $post['External_care_id'];
  274. $items[$externalId] = $post;
  275. }
  276. ksort($items);
  277. foreach ($items as $row) {
  278. // Insert user
  279. //$insertUserInfo = api_get_user_info_from_username($row['Added_by']);
  280. // User about the post
  281. $userId = UserManager::get_user_id_from_original_id(
  282. $row['Added_by'],
  283. $this->extraFieldIdNameList['user']
  284. );
  285. $insertUserInfo = api_get_user_info($userId);
  286. if (empty($insertUserInfo)) {
  287. $this->logger->addInfo("User: '".$row['Added_by']."' doesn't exists. Skip this entry.");
  288. continue;
  289. }
  290. $insertUserInfo = api_get_user_entity($insertUserInfo['user_id']);
  291. // User about the post
  292. $userId = UserManager::get_user_id_from_original_id(
  293. $row['External_user_id'],
  294. $this->extraFieldIdNameList['user']
  295. );
  296. if (empty($userId)) {
  297. $this->logger->addInfo("User does '".$row['External_user_id']."' not exists skip this entry.");
  298. continue;
  299. }
  300. $userInfo = api_get_user_entity($userId);
  301. if (empty($userInfo)) {
  302. $this->logger->addInfo("Chamilo user does not found: #".$userId."' ");
  303. continue;
  304. }
  305. // Dates
  306. $createdAt = $this->createDateTime($row['Added_On']);
  307. $updatedAt = $this->createDateTime($row['Edited_on']);
  308. // Parent
  309. $parent = null;
  310. if (!empty($row['Parent_id'])) {
  311. $parentId = $items[$row['Parent_id']];
  312. $criteria = [
  313. 'externalCareId' => $parentId,
  314. ];
  315. $parent = $em->getRepository('ChamiloPluginBundle:StudentFollowUp\CarePost')->findOneBy($criteria);
  316. }
  317. // Tags
  318. $tags = explode(',', $row['Tags']);
  319. // Check if post already was added:
  320. $criteria = [
  321. 'externalCareId' => $row['External_care_id'],
  322. ];
  323. $post = $em->getRepository('ChamiloPluginBundle:StudentFollowUp\CarePost')->findOneBy($criteria);
  324. if (empty($post)) {
  325. $post = new CarePost();
  326. $this->logger->addInfo("New post will be created no match for externalCareId = ".$row['External_care_id']);
  327. }
  328. $contentDecoded = base64_decode($row['Article']);
  329. $post
  330. ->setTitle($row['Title'])
  331. ->setContent($contentDecoded)
  332. ->setExternalCareId($row['External_care_id'])
  333. ->setCreatedAt($createdAt)
  334. ->setUpdatedAt($updatedAt)
  335. ->setPrivate((int) $row['Private'])
  336. ->setInsertUser($insertUserInfo)
  337. ->setExternalSource((int) $row['Source_is_external'])
  338. ->setParent($parent)
  339. ->setTags($tags)
  340. ->setUser($userInfo)
  341. ->setAttachment($row['Attachement'])
  342. ;
  343. $em->persist($post);
  344. $em->flush();
  345. $this->logger->addInfo("Post id saved #".$post->getId());
  346. if (($counter % $batchSize) === 0) {
  347. $em->flush();
  348. $em->clear(); // Detaches all objects from Doctrine!
  349. }
  350. $counter++;
  351. }
  352. $em->clear(); // Detaches all objects from Doctrine!
  353. }
  354. }
  355. /**
  356. * @return mixed
  357. */
  358. public function getUpdateEmailToDummy()
  359. {
  360. return $this->updateEmailToDummy;
  361. }
  362. /**
  363. * @param mixed $updateEmailToDummy
  364. */
  365. public function setUpdateEmailToDummy($updateEmailToDummy)
  366. {
  367. $this->updateEmailToDummy = $updateEmailToDummy;
  368. }
  369. /**
  370. * Change emails of all users except admins.
  371. */
  372. public function updateUsersEmails()
  373. {
  374. if ($this->getUpdateEmailToDummy() === true) {
  375. $sql = "UPDATE user SET email = CONCAT(username,'@example.com') WHERE id NOT IN (SELECT user_id FROM admin)";
  376. Database::query($sql);
  377. }
  378. }
  379. /**
  380. * Prepares extra fields before the import.
  381. */
  382. private function prepareImport()
  383. {
  384. // Create user extra field: extra_external_user_id
  385. UserManager::create_extra_field(
  386. $this->extraFieldIdNameList['user'],
  387. 1,
  388. 'External user id',
  389. null
  390. );
  391. // Create course extra field: extra_external_course_id
  392. CourseManager::create_course_extra_field(
  393. $this->extraFieldIdNameList['course'],
  394. 1,
  395. 'External course id',
  396. ''
  397. );
  398. CourseManager::create_course_extra_field(
  399. 'disable_import_calendar',
  400. 13,
  401. 'Disable import calendar',
  402. ''
  403. );
  404. // Create session extra field extra_external_session_id
  405. SessionManager::create_session_extra_field(
  406. $this->extraFieldIdNameList['session'],
  407. 1,
  408. 'External session id'
  409. );
  410. SessionManager::create_session_extra_field(
  411. $this->extraFieldIdNameList['session_career'],
  412. 1,
  413. 'Career id'
  414. );
  415. // Create calendar_event extra field extra_external_session_id
  416. $extraField = new ExtraField('calendar_event');
  417. $extraField->save(
  418. [
  419. 'field_type' => ExtraField::FIELD_TYPE_TEXT,
  420. 'variable' => $this->extraFieldIdNameList['calendar_event'],
  421. 'display_text' => 'External calendar event id',
  422. ]
  423. );
  424. $extraField = new ExtraField('career');
  425. $extraField->save(
  426. [
  427. 'visible_to_self' => 1,
  428. 'field_type' => ExtraField::FIELD_TYPE_TEXT,
  429. 'variable' => $this->extraFieldIdNameList['career'],
  430. 'display_text' => 'External career id',
  431. ]
  432. );
  433. $extraField->save(
  434. [
  435. 'visible_to_self' => 1,
  436. 'field_type' => ExtraField::FIELD_TYPE_TEXTAREA,
  437. 'variable' => $this->extraFieldIdNameList['career_diagram'],
  438. 'display_text' => 'Career diagram',
  439. ]
  440. );
  441. $extraField->save(
  442. [
  443. 'visible_to_self' => 1,
  444. 'field_type' => ExtraField::FIELD_TYPE_TEXTAREA,
  445. 'variable' => $this->extraFieldIdNameList['career_urls'],
  446. 'display_text' => 'Career urls',
  447. ]
  448. );
  449. }
  450. /**
  451. * @param string $file
  452. */
  453. private function moveFile($file)
  454. {
  455. $moved = str_replace('incoming', 'treated', $file);
  456. if ($this->test) {
  457. $result = 1;
  458. } else {
  459. $result = rename($file, $moved);
  460. }
  461. if ($result) {
  462. $this->logger->addInfo("Moving file to the treated folder: $file");
  463. } else {
  464. $this->logger->addError(
  465. "Error - Cant move file to the treated folder: $file"
  466. );
  467. }
  468. }
  469. /**
  470. * @param array $row
  471. *
  472. * @return array
  473. */
  474. private function cleanUserRow($row)
  475. {
  476. $row['lastname'] = $row['LastName'];
  477. $row['firstname'] = $row['FirstName'];
  478. $row['email'] = $row['Email'];
  479. $row['username'] = $row['UserName'];
  480. $row['password'] = $row['Password'];
  481. $row['auth_source'] = isset($row['AuthSource']) ? $row['AuthSource'] : PLATFORM_AUTH_SOURCE;
  482. $row['official_code'] = $row['OfficialCode'];
  483. $row['phone'] = isset($row['PhoneNumber']) ? $row['PhoneNumber'] : '';
  484. if (isset($row['StudentID'])) {
  485. $row['extra_'.$this->extraFieldIdNameList['user']] = $row['StudentID'];
  486. }
  487. if (isset($row['TeacherID'])) {
  488. $row['extra_'.$this->extraFieldIdNameList['user']] = $row['TeacherID'];
  489. }
  490. return $row;
  491. }
  492. /**
  493. * @param array $row
  494. *
  495. * @return array
  496. */
  497. private function cleanCourseRow($row)
  498. {
  499. $row['title'] = $row['Title'];
  500. $row['course_code'] = $row['Code'];
  501. $row['course_category'] = $row['CourseCategory'];
  502. $row['email'] = $row['Teacher'];
  503. $row['language'] = $row['Language'];
  504. $row['visibility'] = isset($row['Visibility']) ? $row['Visibility'] : COURSE_VISIBILITY_REGISTERED;
  505. $row['teachers'] = [];
  506. if (isset($row['Teacher']) && !empty($row['Teacher'])) {
  507. $this->logger->addInfo("Teacher list found: ".$row['Teacher']);
  508. $teachers = explode(',', $row['Teacher']);
  509. if (!empty($teachers)) {
  510. foreach ($teachers as $teacherUserName) {
  511. $teacherUserName = trim($teacherUserName);
  512. $userInfo = api_get_user_info_from_username($teacherUserName);
  513. if (!empty($userInfo)) {
  514. $this->logger->addInfo("Username found: $teacherUserName");
  515. $row['teachers'][] = $userInfo['user_id'];
  516. }
  517. }
  518. }
  519. }
  520. if (isset($row['CourseID'])) {
  521. $row['extra_'.$this->extraFieldIdNameList['course']] = $row['CourseID'];
  522. }
  523. return $row;
  524. }
  525. /**
  526. * File to import.
  527. *
  528. * @param string $file
  529. */
  530. private function importTeachersStatic($file)
  531. {
  532. $this->importTeachers($file, true);
  533. }
  534. /**
  535. * File to import.
  536. *
  537. * @param string $file
  538. * @param bool $moveFile
  539. */
  540. private function importTeachers($file, $moveFile = true)
  541. {
  542. $this->fixCSVFile($file);
  543. $data = Import::csvToArray($file);
  544. /* Unique identifier: official-code username.
  545. Email address and password should never get updated. *ok
  546. The only fields that I can think of that should update if the data changes in the csv file are FirstName and LastName. *ok
  547. A slight edit of these fields should be taken into account. ???
  548. Adding teachers is no problem, but deleting them shouldn’t be automated, but we should get a log of “to delete teachers”.
  549. We’ll handle that manually if applicable.
  550. No delete!
  551. */
  552. $language = $this->defaultLanguage;
  553. if (!empty($data)) {
  554. $this->logger->addInfo(count($data)." records found.");
  555. $expirationDateOnCreation = api_get_utc_datetime(strtotime("+".intval($this->expirationDateInUserCreation)."years"));
  556. $expirationDateOnUpdate = api_get_utc_datetime(strtotime("+".intval($this->expirationDateInUserUpdate)."years"));
  557. $batchSize = $this->batchSize;
  558. $em = Database::getManager();
  559. $counter = 1;
  560. foreach ($data as $row) {
  561. $row = $this->cleanUserRow($row);
  562. $user_id = UserManager::get_user_id_from_original_id(
  563. $row['extra_'.$this->extraFieldIdNameList['user']],
  564. $this->extraFieldIdNameList['user']
  565. );
  566. $userInfo = [];
  567. $userInfoByOfficialCode = null;
  568. if (!empty($user_id)) {
  569. $userInfo = api_get_user_info($user_id);
  570. $userInfoByOfficialCode = api_get_user_info_from_official_code($row['official_code']);
  571. }
  572. if (empty($userInfo) && empty($userInfoByOfficialCode)) {
  573. // Create user
  574. $userId = UserManager::create_user(
  575. $row['firstname'],
  576. $row['lastname'],
  577. COURSEMANAGER,
  578. $row['email'],
  579. $row['username'],
  580. $row['password'],
  581. $row['official_code'],
  582. $language, //$row['language'],
  583. $row['phone'],
  584. null, //$row['picture'], //picture
  585. $row['auth_source'], // ?
  586. $expirationDateOnCreation, //'0000-00-00 00:00:00', //$row['expiration_date'], //$expiration_date = '0000-00-00 00:00:00',
  587. 1, //active
  588. 0,
  589. null, // extra
  590. null, //$encrypt_method = '',
  591. false //$send_mail = false
  592. );
  593. $row['extra_mail_notify_invitation'] = 1;
  594. $row['extra_mail_notify_message'] = 1;
  595. $row['extra_mail_notify_group_message'] = 1;
  596. if ($userId) {
  597. foreach ($row as $key => $value) {
  598. if (substr($key, 0, 6) == 'extra_') {
  599. //an extra field
  600. UserManager::update_extra_field_value(
  601. $userId,
  602. substr($key, 6),
  603. $value
  604. );
  605. }
  606. }
  607. $this->logger->addInfo("Teachers - User created: ".$row['username']);
  608. } else {
  609. $this->logger->addError("Teachers - User NOT created: ".$row['username']." ".$row['firstname']." ".$row['lastname']);
  610. $this->logger->addError(strip_tags(Display::getFlashToString()));
  611. Display::cleanFlashMessages();
  612. }
  613. } else {
  614. if (empty($userInfo)) {
  615. $this->logger->addError("Teachers - Can't update user :".$row['username']);
  616. continue;
  617. }
  618. // Update user
  619. $result = UserManager::update_user(
  620. $userInfo['user_id'],
  621. $row['firstname'], // <<-- changed
  622. $row['lastname'], // <<-- changed
  623. $userInfo['username'],
  624. null, //$password = null,
  625. $row['auth_source'],
  626. $userInfo['email'],
  627. COURSEMANAGER,
  628. $userInfo['official_code'],
  629. $userInfo['phone'],
  630. $userInfo['picture_uri'],
  631. $expirationDateOnUpdate,
  632. $userInfo['active'],
  633. null, //$creator_id = null,
  634. 0, //$hr_dept_id = 0,
  635. null, // $extra = null,
  636. null, //$language = 'english',
  637. null, //$encrypt_method = '',
  638. false, //$send_email = false,
  639. 0 //$reset_password = 0
  640. );
  641. if ($result) {
  642. foreach ($row as $key => $value) {
  643. if (substr($key, 0, 6) == 'extra_') {
  644. //an extra field
  645. UserManager::update_extra_field_value(
  646. $userInfo['user_id'],
  647. substr($key, 6),
  648. $value
  649. );
  650. }
  651. }
  652. $this->logger->addInfo("Teachers - User updated: ".$row['username']);
  653. } else {
  654. $this->logger->addError("Teachers - User not updated: ".$row['username']);
  655. }
  656. }
  657. if (($counter % $batchSize) === 0) {
  658. $em->flush();
  659. $em->clear(); // Detaches all objects from Doctrine!
  660. }
  661. $counter++;
  662. }
  663. $em->clear(); // Detaches all objects from Doctrine!
  664. }
  665. if ($moveFile) {
  666. $this->moveFile($file);
  667. }
  668. $this->updateUsersEmails();
  669. }
  670. /**
  671. * @param string $file
  672. */
  673. private function importStudentsStatic($file)
  674. {
  675. $this->importStudents($file, true);
  676. }
  677. /**
  678. * @param string $file
  679. * @param bool $moveFile
  680. */
  681. private function importStudents($file, $moveFile = true)
  682. {
  683. $this->fixCSVFile($file);
  684. $data = Import::csvToArray($file);
  685. /*
  686. * Another users import.
  687. Unique identifier: official code and username . ok
  688. Password should never get updated. ok
  689. If an update should need to occur (because it changed in the .csv),
  690. we’ll want that logged. We will handle this manually in that case.
  691. All other fields should be updateable, though passwords should of course not get updated. ok
  692. If a user gets deleted (not there anymore),
  693. He should be set inactive one year after the current date.
  694. So I presume you’ll just update the expiration date.
  695. We want to grant access to courses up to a year after deletion.
  696. */
  697. $timeStart = microtime(true);
  698. $batchSize = $this->batchSize;
  699. $em = Database::getManager();
  700. if (!empty($data)) {
  701. $language = $this->defaultLanguage;
  702. $this->logger->addInfo(count($data)." records found.");
  703. $expirationDateOnCreate = api_get_utc_datetime(
  704. strtotime("+".intval($this->expirationDateInUserCreation)."years")
  705. );
  706. $expirationDateOnUpdate = api_get_utc_datetime(
  707. strtotime("+".intval($this->expirationDateInUserUpdate)."years")
  708. );
  709. $counter = 1;
  710. $secondsInYear = 365 * 24 * 60 * 60;
  711. foreach ($data as $row) {
  712. $row = $this->cleanUserRow($row);
  713. $user_id = UserManager::get_user_id_from_original_id(
  714. $row['extra_'.$this->extraFieldIdNameList['user']],
  715. $this->extraFieldIdNameList['user']
  716. );
  717. $userInfo = [];
  718. $userInfoByOfficialCode = null;
  719. if (!empty($user_id)) {
  720. $userInfo = api_get_user_info($user_id, false, true);
  721. $userInfoByOfficialCode = api_get_user_info_from_official_code($row['official_code']);
  722. }
  723. if (empty($userInfo) && empty($userInfoByOfficialCode)) {
  724. // Create user
  725. $result = UserManager::create_user(
  726. $row['firstname'],
  727. $row['lastname'],
  728. STUDENT,
  729. $row['email'],
  730. $row['username'],
  731. $row['password'],
  732. $row['official_code'],
  733. $language, //$row['language'],
  734. $row['phone'],
  735. null, //$row['picture'], //picture
  736. $row['auth_source'], // ?
  737. $expirationDateOnCreate, //'0000-00-00 00:00:00', //$row['expiration_date'], //$expiration_date = '0000-00-00 00:00:00',
  738. 1, //active
  739. 0,
  740. null, // extra
  741. null, //$encrypt_method = '',
  742. false //$send_mail = false
  743. );
  744. $row['extra_mail_notify_invitation'] = 1;
  745. $row['extra_mail_notify_message'] = 1;
  746. $row['extra_mail_notify_group_message'] = 1;
  747. if ($result) {
  748. foreach ($row as $key => $value) {
  749. if (substr($key, 0, 6) === 'extra_') {
  750. //an extra field
  751. UserManager::update_extra_field_value(
  752. $result,
  753. substr($key, 6),
  754. $value
  755. );
  756. }
  757. }
  758. $this->logger->addInfo("Students - User created: ".$row['username']);
  759. } else {
  760. $this->logger->addError("Students - User NOT created: ".$row['username']." ".$row['firstname']." ".$row['lastname']);
  761. $this->logger->addError(strip_tags(Display::getFlashToString()));
  762. Display::cleanFlashMessages();
  763. }
  764. } else {
  765. if (empty($userInfo)) {
  766. $this->logger->addError("Students - Can't update user :".$row['username']);
  767. continue;
  768. }
  769. if (isset($row['action']) && $row['action'] === 'delete') {
  770. // Inactive one year later
  771. $userInfo['expiration_date'] = api_get_utc_datetime(api_strtotime(time() + $secondsInYear));
  772. }
  773. $password = $row['password']; // change password
  774. $email = $row['email']; // change email
  775. $resetPassword = 2; // allow password change
  776. // Conditions that disables the update of password and email:
  777. if (isset($this->conditions['importStudents'])) {
  778. if (isset($this->conditions['importStudents']['update']) &&
  779. isset($this->conditions['importStudents']['update']['avoid'])
  780. ) {
  781. // Blocking email update -
  782. // 1. Condition
  783. $avoidUsersWithEmail = $this->conditions['importStudents']['update']['avoid']['email'];
  784. if ($userInfo['email'] != $row['email'] && in_array($row['email'], $avoidUsersWithEmail)) {
  785. $this->logger->addInfo("Students - User email is not updated : ".$row['username']." because the avoid conditions (email).");
  786. // Do not change email keep the old email.
  787. $email = $userInfo['email'];
  788. }
  789. // 2. Condition
  790. if (!in_array($userInfo['email'], $avoidUsersWithEmail) && !in_array($row['email'], $avoidUsersWithEmail)) {
  791. $email = $userInfo['email'];
  792. }
  793. // 3. Condition
  794. if (in_array($userInfo['email'], $avoidUsersWithEmail) && !in_array($row['email'], $avoidUsersWithEmail)) {
  795. $email = $row['email'];
  796. }
  797. // Blocking password update
  798. //$avoidUsersWithPassword = $this->conditions['importStudents']['update']['avoid']['password'];
  799. /*if (isset($row['password'])) {
  800. $user = api_get_user_entity($userInfo['id']);
  801. $encoded = UserManager::encryptPassword(
  802. $row['password'],
  803. $user
  804. );
  805. if ($userInfo['password'] != $encoded &&
  806. in_array($row['password'], $avoidUsersWithPassword)
  807. ) {
  808. $this->logger->addInfo(
  809. "Students - User password is not updated: ".$row['username']." because the avoid conditions (password)."
  810. );
  811. $password = null;
  812. $resetPassword = 0; // disallow password change
  813. }
  814. }*/
  815. }
  816. }
  817. // Always disallow password change during update
  818. $password = null;
  819. $resetPassword = 0; // disallow password change
  820. // Update user
  821. $result = UserManager::update_user(
  822. $userInfo['user_id'],
  823. $row['firstname'], // <<-- changed
  824. $row['lastname'], // <<-- changed
  825. $row['username'], // <<-- changed
  826. $password, //$password = null,
  827. $row['auth_source'],
  828. $email,
  829. STUDENT,
  830. $userInfo['official_code'],
  831. $userInfo['phone'],
  832. $userInfo['picture_uri'],
  833. $expirationDateOnUpdate,
  834. $userInfo['active'],
  835. null, //$creator_id = null,
  836. 0, //$hr_dept_id = 0,
  837. null, // $extra = null,
  838. null, //$language = 'english',
  839. null, //$encrypt_method = '',
  840. false, //$send_email = false,
  841. $resetPassword //$reset_password = 0
  842. );
  843. if ($result) {
  844. if ($row['username'] != $userInfo['username']) {
  845. $this->logger->addInfo("Students - Username was changes from '".$userInfo['username']."' to '".$row['username']."' ");
  846. }
  847. foreach ($row as $key => $value) {
  848. if (substr($key, 0, 6) === 'extra_') {
  849. //an extra field
  850. UserManager::update_extra_field_value(
  851. $userInfo['user_id'],
  852. substr($key, 6),
  853. $value
  854. );
  855. }
  856. }
  857. $this->logger->addInfo("Students - User updated: ".$row['username']);
  858. } else {
  859. $this->logger->addError("Students - User NOT updated: ".$row['username']." ".$row['firstname']." ".$row['lastname']);
  860. }
  861. }
  862. if (($counter % $batchSize) === 0) {
  863. $em->flush();
  864. $em->clear(); // Detaches all objects from Doctrine!
  865. $this->logger->addInfo("Detaches all objects");
  866. }
  867. $counter++;
  868. }
  869. $em->clear(); // Detaches all objects from Doctrine!
  870. }
  871. $timeEnd = microtime(true);
  872. $executionTime = round(($timeEnd - $timeStart) / 60, 2);
  873. $this->logger->addInfo("Execution Time for process students: $executionTime Min");
  874. if ($moveFile) {
  875. $this->moveFile($file);
  876. }
  877. $this->updateUsersEmails();
  878. }
  879. /**
  880. * @param string $file
  881. */
  882. private function importCoursesStatic($file, $moveFile, &$teacherBackup = [], &$groupBackup = [])
  883. {
  884. $this->importCourses($file, true, $teacherBackup, $groupBackup);
  885. }
  886. /**
  887. * @param string $file
  888. * @param bool $moveFile
  889. *
  890. * @return int
  891. */
  892. private function importCalendarStatic($file, $moveFile = true)
  893. {
  894. $this->fixCSVFile($file);
  895. $this->updateUsersEmails();
  896. $data = Import::csvToArray($file);
  897. if (!empty($data)) {
  898. $this->logger->addInfo(count($data)." records found.");
  899. $eventsToCreate = [];
  900. $errorFound = false;
  901. $courseExtraFieldValue = new ExtraFieldValue('course');
  902. foreach ($data as $row) {
  903. $sessionId = null;
  904. $externalSessionId = null;
  905. if (isset($row['external_sessionID'])) {
  906. $externalSessionId = $row['external_sessionID'];
  907. $sessionId = SessionManager::getSessionIdFromOriginalId(
  908. $externalSessionId,
  909. $this->extraFieldIdNameList['session']
  910. );
  911. }
  912. $courseCode = null;
  913. if (isset($row['coursecode'])) {
  914. $courseCode = $row['coursecode'];
  915. }
  916. $courseInfo = api_get_course_info($courseCode);
  917. $item = $courseExtraFieldValue->get_values_by_handler_and_field_variable(
  918. $courseInfo['real_id'],
  919. 'disable_import_calendar'
  920. );
  921. if (!empty($item) && isset($item['value']) && $item['value'] == 1) {
  922. $this->logger->addInfo(
  923. "Course '".$courseInfo['code']."' has 'disable_import_calendar' turn on. Skip"
  924. );
  925. $errorFound = true;
  926. }
  927. if (empty($courseInfo)) {
  928. $this->logger->addInfo("Course '$courseCode' does not exists");
  929. } else {
  930. if ($courseInfo['visibility'] == COURSE_VISIBILITY_HIDDEN) {
  931. $this->logger->addInfo("Course '".$courseInfo['code']."' has hidden visiblity. Skip");
  932. $errorFound = true;
  933. }
  934. }
  935. if (empty($sessionId)) {
  936. $this->logger->addInfo("external_sessionID: $externalSessionId does not exists.");
  937. }
  938. $teacherId = null;
  939. $sessionInfo = [];
  940. if (!empty($sessionId) && !empty($courseInfo)) {
  941. $sessionInfo = api_get_session_info($sessionId);
  942. $courseIncluded = SessionManager::relation_session_course_exist(
  943. $sessionId,
  944. $courseInfo['real_id']
  945. );
  946. if ($courseIncluded == false) {
  947. $this->logger->addInfo(
  948. "Course '$courseCode' is not included in session: $sessionId"
  949. );
  950. $errorFound = true;
  951. } else {
  952. $teachers = CourseManager::get_coach_list_from_course_code(
  953. $courseInfo['code'],
  954. $sessionId
  955. );
  956. // Getting first teacher.
  957. if (!empty($teachers)) {
  958. $teacher = current($teachers);
  959. $teacherId = $teacher['user_id'];
  960. } else {
  961. $teacherId = $sessionInfo['id_coach'];
  962. }
  963. }
  964. } else {
  965. $errorFound = true;
  966. }
  967. if (empty($teacherId)) {
  968. $errorFound = true;
  969. $this->logger->addInfo(
  970. "No teacher found in course code : '$courseCode' and session: '$sessionId'"
  971. );
  972. }
  973. $date = $row['date'];
  974. $startTime = $row['time_start'];
  975. $endTime = $row['time_end'];
  976. $title = $row['title'];
  977. $comment = $row['comment'];
  978. $color = isset($row['color']) ? $row['color'] : '';
  979. $startDateYear = substr($date, 0, 4);
  980. $startDateMonth = substr($date, 4, 2);
  981. $startDateDay = substr($date, 6, 8);
  982. $startDate = $startDateYear.'-'.$startDateMonth.'-'.$startDateDay.' '.$startTime.':00';
  983. $endDate = $startDateYear.'-'.$startDateMonth.'-'.$startDateDay.' '.$endTime.':00';
  984. if (!api_is_valid_date($startDate) || !api_is_valid_date($endDate)) {
  985. $this->logger->addInfo("Verify your dates: '$startDate' : '$endDate' ");
  986. $errorFound = true;
  987. }
  988. // Check session dates
  989. if ($sessionInfo && !empty($sessionInfo['access_start_date'])) {
  990. $date = new \DateTime($sessionInfo['access_start_date']);
  991. $interval = new \DateInterval('P7D');
  992. $date->sub($interval);
  993. if ($date->getTimestamp() > time()) {
  994. $this->logger->addInfo(
  995. "Calendar event # ".$row['external_calendar_itemID']."
  996. in session [$externalSessionId] was not added
  997. because the startdate is more than 7 days in the future: ".$sessionInfo['access_start_date']
  998. );
  999. $errorFound = true;
  1000. }
  1001. }
  1002. if ($errorFound == false) {
  1003. $eventsToCreate[] = [
  1004. 'start' => $startDate,
  1005. 'end' => $endDate,
  1006. 'title' => $title,
  1007. 'sender_id' => $teacherId,
  1008. 'course_id' => $courseInfo['real_id'],
  1009. 'session_id' => $sessionId,
  1010. 'comment' => $comment,
  1011. 'color' => $color,
  1012. $this->extraFieldIdNameList['calendar_event'] => $row['external_calendar_itemID'],
  1013. ];
  1014. }
  1015. $errorFound = false;
  1016. }
  1017. if (empty($eventsToCreate)) {
  1018. $this->logger->addInfo('No events to add');
  1019. return 0;
  1020. }
  1021. $extraFieldValue = new ExtraFieldValue('calendar_event');
  1022. $extraFieldName = $this->extraFieldIdNameList['calendar_event'];
  1023. $externalEventId = null;
  1024. $extraField = new ExtraField('calendar_event');
  1025. $extraFieldInfo = $extraField->get_handler_field_info_by_field_variable($extraFieldName);
  1026. if (empty($extraFieldInfo)) {
  1027. $this->logger->addInfo(
  1028. "No calendar event extra field created: $extraFieldName"
  1029. );
  1030. return 0;
  1031. }
  1032. $this->logger->addInfo('Ready to insert # '.count($eventsToCreate).' events');
  1033. $batchSize = $this->batchSize;
  1034. $counter = 1;
  1035. $em = Database::getManager();
  1036. $eventStartDateList = [];
  1037. $eventEndDateList = [];
  1038. $report = [
  1039. 'mail_sent' => 0,
  1040. 'mail_not_sent_announcement_exists' => 0,
  1041. 'mail_not_sent_because_date' => 0,
  1042. ];
  1043. $eventsToCreateFinal = [];
  1044. foreach ($eventsToCreate as $event) {
  1045. $update = false;
  1046. $item = null;
  1047. if (!isset($event[$extraFieldName])) {
  1048. $this->logger->addInfo(
  1049. "No external_calendar_itemID found. Skipping ..."
  1050. );
  1051. continue;
  1052. } else {
  1053. $externalEventId = $event[$extraFieldName];
  1054. if (empty($externalEventId)) {
  1055. $this->logger->addInfo(
  1056. "external_calendar_itemID was set but empty. Skipping ..."
  1057. );
  1058. continue;
  1059. }
  1060. $item = $extraFieldValue->get_item_id_from_field_variable_and_field_value(
  1061. $extraFieldName,
  1062. $externalEventId,
  1063. false,
  1064. false,
  1065. false
  1066. );
  1067. if (!empty($item)) {
  1068. $update = true;
  1069. }
  1070. }
  1071. $courseInfo = api_get_course_info_by_id($event['course_id']);
  1072. $event['course_info'] = $courseInfo;
  1073. $event['update'] = $update;
  1074. $event['item'] = $item;
  1075. $calendarEvent = null;
  1076. /* Check if event changed of course code */
  1077. if (!empty($item) && isset($item['item_id']) && !empty($item['item_id'])) {
  1078. /** @var CCalendarEvent $calendarEvent */
  1079. $calendarEvent = $em->getRepository('ChamiloCourseBundle:CCalendarEvent')->find($item['item_id']);
  1080. }
  1081. if ($calendarEvent) {
  1082. $this->logger->addInfo('Calendar event found '.$item['item_id']);
  1083. if ($calendarEvent->getCId() != $courseInfo['real_id']) {
  1084. $this->logger->addInfo('Move from course #'.$calendarEvent->getCId().' to #'.$courseInfo['real_id']);
  1085. // Seems that the course id changed in the csv
  1086. $calendarEvent->setCId($courseInfo['real_id']);
  1087. $em->persist($calendarEvent);
  1088. $em->flush();
  1089. $criteria = [
  1090. 'tool' => 'calendar_event',
  1091. 'ref' => $item['item_id'],
  1092. ];
  1093. /** @var CItemProperty $itemProperty */
  1094. $itemProperty = $em->getRepository('ChamiloCourseBundle:CItemProperty')->findOneBy($criteria);
  1095. $courseEntity = $em->getRepository('ChamiloCoreBundle:Course')->find($courseInfo['real_id']);
  1096. if ($itemProperty && $courseEntity) {
  1097. $itemProperty->setCourse($courseEntity);
  1098. $em->persist($itemProperty);
  1099. $em->flush();
  1100. }
  1101. }
  1102. $this->logger->addInfo('Move from course #'.$calendarEvent->getCId().' to #'.$courseInfo['real_id']);
  1103. // Checking if session still exists
  1104. $calendarSessionId = (int) $calendarEvent->getSessionId();
  1105. if (!empty($calendarSessionId)) {
  1106. $calendarSessionInfo = api_get_session_info($calendarSessionId);
  1107. if (empty($calendarSessionInfo)) {
  1108. $calendarId = (int) $calendarEvent->getIid();
  1109. // Delete calendar events because the session was deleted!
  1110. $this->logger->addInfo(
  1111. "Delete event # $calendarId because session # $calendarSessionId doesn't exist"
  1112. );
  1113. $sql = "DELETE FROM c_calendar_event
  1114. WHERE iid = $calendarId AND session_id = $calendarSessionId";
  1115. Database::query($sql);
  1116. $this->logger->addInfo($sql);
  1117. $sql = "DELETE FROM c_item_property
  1118. WHERE
  1119. tool = 'calendar_event' AND
  1120. ref = $calendarSessionId AND
  1121. session_id = $calendarSessionId";
  1122. Database::query($sql);
  1123. $this->logger->addInfo($sql);
  1124. }
  1125. }
  1126. } else {
  1127. $this->logger->addInfo('Calendar event not found '.$item['item_id']);
  1128. }
  1129. $event['external_event_id'] = $externalEventId;
  1130. if (isset($eventStartDateList[$courseInfo['real_id']]) &&
  1131. isset($eventStartDateList[$courseInfo['real_id']][$event['session_id']])
  1132. ) {
  1133. $currentItemDate = api_strtotime($event['start']);
  1134. $firstDate = $eventStartDateList[$courseInfo['real_id']][$event['session_id']];
  1135. if ($currentItemDate < api_strtotime($firstDate)) {
  1136. $eventStartDateList[$courseInfo['real_id']][$event['session_id']] = $event['start'];
  1137. $eventEndDateList[$courseInfo['real_id']][$event['session_id']] = $event['end'];
  1138. }
  1139. } else {
  1140. // First time
  1141. $eventStartDateList[$courseInfo['real_id']][$event['session_id']] = $event['start'];
  1142. $eventEndDateList[$courseInfo['real_id']][$event['session_id']] = $event['end'];
  1143. }
  1144. $eventsToCreateFinal[] = $event;
  1145. }
  1146. $eventAlreadySent = [];
  1147. foreach ($eventsToCreateFinal as $event) {
  1148. $courseInfo = $event['course_info'];
  1149. $item = $event['item'];
  1150. $update = $event['update'];
  1151. $externalEventId = $event['external_event_id'];
  1152. $info = 'Course: '.$courseInfo['real_id'].' ('.$courseInfo['code'].') - Session: '.$event['session_id'].' external event id: '.$externalEventId;
  1153. $agenda = new Agenda(
  1154. 'course',
  1155. $event['sender_id'],
  1156. $courseInfo['real_id'],
  1157. $event['session_id']
  1158. );
  1159. $agenda->set_course($courseInfo);
  1160. $agenda->setSessionId($event['session_id']);
  1161. $agenda->setSenderId($event['sender_id']);
  1162. $agenda->setIsAllowedToEdit(true);
  1163. $eventComment = $event['comment'];
  1164. $color = $event['color'];
  1165. // To use the event comment you need
  1166. // ALTER TABLE c_calendar_event ADD COLUMN comment TEXT;
  1167. // add in configuration.php allow_agenda_event_comment = true
  1168. if (empty($courseInfo)) {
  1169. $this->logger->addInfo(
  1170. "No course found for event #$externalEventId Course #".$event['course_id']." Skipping ..."
  1171. );
  1172. continue;
  1173. }
  1174. if (empty($event['sender_id'])) {
  1175. $this->logger->addInfo(
  1176. "No sender found for event #$externalEventId Send #".$event['sender_id']." Skipping ..."
  1177. );
  1178. continue;
  1179. }
  1180. // Taking first element of course-session event
  1181. $alreadyAdded = false;
  1182. $firstDate = $eventStartDateList[$courseInfo['real_id']][$event['session_id']];
  1183. $firstEndDate = $eventEndDateList[$courseInfo['real_id']][$event['session_id']];
  1184. if (isset($eventAlreadySent[$courseInfo['real_id']]) &&
  1185. isset($eventAlreadySent[$courseInfo['real_id']][$event['session_id']])
  1186. ) {
  1187. $alreadyAdded = true;
  1188. } else {
  1189. $eventAlreadySent[$courseInfo['real_id']][$event['session_id']] = true;
  1190. }
  1191. // Working days (Mon-Fri)see BT#12156#note-16
  1192. $days = 5;
  1193. $startDatePlusDays = api_strtotime("$days weekdays");
  1194. /*
  1195. $timePart = date('H:i:s', api_strtotime('now'));
  1196. $datePart = date('Y-m-d', api_strtotime("$days weekdays"));
  1197. $startDatePlusDays = "$timePart $datePart";
  1198. */
  1199. $this->logger->addInfo(
  1200. "startDatePlusDays: ".api_get_utc_datetime($startDatePlusDays).' - First date: '.$firstDate
  1201. );
  1202. // Send
  1203. $sendMail = false;
  1204. if ($startDatePlusDays > api_strtotime($firstDate)) {
  1205. $sendMail = true;
  1206. }
  1207. // Send announcement to users
  1208. if ($sendMail && $alreadyAdded == false) {
  1209. $start = $firstDate;
  1210. $end = $firstEndDate;
  1211. if (!empty($end) &&
  1212. api_format_date($start, DATE_FORMAT_LONG) == api_format_date($end, DATE_FORMAT_LONG)
  1213. ) {
  1214. $date = api_format_date($start, DATE_FORMAT_LONG).' ('.
  1215. api_format_date($start, TIME_NO_SEC_FORMAT).' '.
  1216. api_format_date($end, TIME_NO_SEC_FORMAT).')';
  1217. } else {
  1218. $date = api_format_date($start, DATE_TIME_FORMAT_LONG_24H).' - '.
  1219. api_format_date($end, DATE_TIME_FORMAT_LONG_24H);
  1220. }
  1221. $sessionName = '';
  1222. if (!empty($event['session_id'])) {
  1223. $sessionName = ' ('.api_get_session_name($event['session_id']).')';
  1224. }
  1225. $courseTitle = $courseInfo['title'].$sessionName;
  1226. $emailBody = get_lang('Dear').' ((user_firstname)) <br />'.
  1227. sprintf(
  1228. get_lang('YouHaveBeenSubscribedToCourseXTheStartDateXAndCommentX'),
  1229. $courseTitle,
  1230. $date,
  1231. $event['comment']
  1232. )
  1233. ;
  1234. $subject = sprintf(
  1235. get_lang('AgendaAvailableInCourseX'),
  1236. $courseInfo['title']
  1237. );
  1238. $coaches = SessionManager::getCoachesByCourseSession(
  1239. $event['session_id'],
  1240. $courseInfo['real_id']
  1241. );
  1242. // Search if an announcement exists:
  1243. $announcementsWithTitleList = AnnouncementManager::getAnnouncementsByTitle(
  1244. $subject,
  1245. $courseInfo['real_id'],
  1246. $event['session_id'],
  1247. 1
  1248. );
  1249. if (count($announcementsWithTitleList) === 0) {
  1250. $this->logger->addInfo(
  1251. "Mail to be sent because start date: ".$event['start']." and no announcement found."
  1252. );
  1253. $senderId = $this->defaultAdminId;
  1254. if (!empty($coaches) && isset($coaches[0]) && !empty($coaches[0])) {
  1255. $senderId = $coaches[0];
  1256. }
  1257. $announcementId = AnnouncementManager::add_announcement(
  1258. $courseInfo,
  1259. $event['session_id'],
  1260. $subject,
  1261. $emailBody,
  1262. [
  1263. 'everyone',
  1264. 'users' => $coaches,
  1265. ],
  1266. [],
  1267. null,
  1268. null,
  1269. false,
  1270. $senderId
  1271. );
  1272. if ($announcementId) {
  1273. $this->logger->addInfo("Announcement added: $announcementId in $info");
  1274. $this->logger->addInfo("<<--SENDING MAIL Sender id: $senderId-->>");
  1275. $report['mail_sent']++;
  1276. AnnouncementManager::sendEmail(
  1277. $courseInfo,
  1278. $event['session_id'],
  1279. $announcementId,
  1280. false,
  1281. false,
  1282. $this->logger,
  1283. $senderId
  1284. );
  1285. } else {
  1286. $this->logger->addError(
  1287. "Error when trying to add announcement with title $subject here: $info and SenderId = $senderId"
  1288. );
  1289. }
  1290. } else {
  1291. $report['mail_not_sent_announcement_exists']++;
  1292. $this->logger->addInfo(
  1293. "Mail NOT sent. An announcement seems to be already saved in '$info'"
  1294. );
  1295. }
  1296. } else {
  1297. $this->logger->addInfo(
  1298. "Send Mail: ".intval($sendMail).' - Already added: '.intval($alreadyAdded)
  1299. );
  1300. if ($sendMail == false) {
  1301. $report['mail_not_sent_because_date']++;
  1302. }
  1303. }
  1304. $content = '';
  1305. if ($update && isset($item['item_id'])) {
  1306. $eventInfo = $agenda->get_event($item['item_id']);
  1307. if (empty($eventInfo)) {
  1308. // Means that agenda external id exists but the event doesn't exist
  1309. $this->logger->addInfo("external event id exists: $externalEventId");
  1310. $this->logger->addInfo("but Chamilo event doesn't exists: ".$item['item_id']);
  1311. $eventId = $agenda->addEvent(
  1312. $event['start'],
  1313. $event['end'],
  1314. false,
  1315. $event['title'],
  1316. $content,
  1317. ['everyone'], // $usersToSend
  1318. false, //$addAsAnnouncement = false
  1319. null, // $parentEventId
  1320. [], //$attachmentArray = array(),
  1321. [], //$attachmentCommentList
  1322. $eventComment,
  1323. $color
  1324. );
  1325. if (!empty($eventId)) {
  1326. $this->logger->addInfo("Chamilo event created: ".$eventId);
  1327. $extraFieldValueItem = $extraFieldValue->get_values_by_handler_and_field_id(
  1328. $item['item_id'],
  1329. $extraFieldInfo['id']
  1330. );
  1331. if (!empty($extraFieldValueItem) && isset($extraFieldValueItem['id'])) {
  1332. $params = [
  1333. 'id' => $extraFieldValueItem['id'],
  1334. 'item_id' => $eventId,
  1335. ];
  1336. $extraFieldValue->update($params);
  1337. $this->logger->addInfo(
  1338. 'Updating calendar extra field #'.$extraFieldValueItem['id'].'
  1339. new item_id: '.$eventId.' old item_id: '.$item['item_id']
  1340. );
  1341. }
  1342. } else {
  1343. $this->logger->addInfo("Error while creating event external id: $externalEventId");
  1344. }
  1345. } else {
  1346. // The event already exists, just update
  1347. $eventResult = $agenda->editEvent(
  1348. $item['item_id'],
  1349. $event['start'],
  1350. $event['end'],
  1351. false,
  1352. $event['title'],
  1353. $content,
  1354. ['everyone'], // $usersToSend
  1355. [], //$attachmentArray = array(),
  1356. [], //$attachmentCommentList
  1357. $eventComment,
  1358. $color,
  1359. false,
  1360. false,
  1361. $this->defaultAdminId
  1362. );
  1363. if ($eventResult !== false) {
  1364. $this->logger->addInfo(
  1365. "Event updated #".$item['item_id']." External cal Id: (".$externalEventId.") $info"
  1366. );
  1367. } else {
  1368. $this->logger->addInfo(
  1369. "Error while updating event with external id: $externalEventId"
  1370. );
  1371. }
  1372. }
  1373. } else {
  1374. // New event. Create it.
  1375. $eventId = $agenda->addEvent(
  1376. $event['start'],
  1377. $event['end'],
  1378. false,
  1379. $event['title'],
  1380. $content,
  1381. ['everyone'], // $usersToSend
  1382. false, //$addAsAnnouncement = false
  1383. null, // $parentEventId
  1384. [], //$attachmentArray = array(),
  1385. [], //$attachmentCommentList
  1386. $eventComment,
  1387. $color
  1388. );
  1389. if (!empty($eventId)) {
  1390. $extraFieldValue->save(
  1391. [
  1392. 'value' => $externalEventId,
  1393. 'field_id' => $extraFieldInfo['id'],
  1394. 'item_id' => $eventId,
  1395. ]
  1396. );
  1397. $this->logger->addInfo(
  1398. "Event added: #$eventId External cal id: (".$externalEventId.") $info"
  1399. );
  1400. } else {
  1401. $this->logger->addInfo(
  1402. "Error while creating event external id: $externalEventId"
  1403. );
  1404. }
  1405. }
  1406. if (($counter % $batchSize) === 0) {
  1407. $em->flush();
  1408. $em->clear(); // Detaches all objects from Doctrine!
  1409. }
  1410. $counter++;
  1411. }
  1412. $em->clear(); // Detaches all objects from Doctrine!
  1413. $this->logger->addInfo('------Summary------');
  1414. foreach ($report as $title => $count) {
  1415. $this->logger->addInfo("$title: $count");
  1416. }
  1417. $this->logger->addInfo('------End Summary------');
  1418. }
  1419. if ($moveFile) {
  1420. $this->moveFile($file);
  1421. }
  1422. }
  1423. /**
  1424. * @param string $file
  1425. * @param bool $moveFile
  1426. * @param array $teacherBackup
  1427. * @param array $groupBackup
  1428. */
  1429. private function importCourses(
  1430. $file,
  1431. $moveFile = true,
  1432. &$teacherBackup = [],
  1433. &$groupBackup = []
  1434. ) {
  1435. $this->fixCSVFile($file);
  1436. $data = Import::csvToArray($file);
  1437. if (!empty($data)) {
  1438. $this->logger->addInfo(count($data)." records found.");
  1439. foreach ($data as $row) {
  1440. $row = $this->cleanCourseRow($row);
  1441. $courseId = CourseManager::get_course_id_from_original_id(
  1442. $row['extra_'.$this->extraFieldIdNameList['course']],
  1443. $this->extraFieldIdNameList['course']
  1444. );
  1445. $courseInfo = api_get_course_info_by_id($courseId);
  1446. if (empty($courseInfo)) {
  1447. // Create
  1448. $params = [];
  1449. $params['title'] = $row['title'];
  1450. $params['exemplary_content'] = false;
  1451. $params['wanted_code'] = $row['course_code'];
  1452. $params['course_category'] = $row['course_category'];
  1453. $params['course_language'] = $row['language'];
  1454. $params['teachers'] = $row['teachers'];
  1455. $params['visibility'] = $row['visibility'];
  1456. $courseInfo = CourseManager::create_course(
  1457. $params,
  1458. $this->defaultAdminId
  1459. );
  1460. if (!empty($courseInfo)) {
  1461. CourseManager::update_course_extra_field_value(
  1462. $courseInfo['code'],
  1463. 'external_course_id',
  1464. $row['extra_'.$this->extraFieldIdNameList['course']]
  1465. );
  1466. $this->logger->addInfo("Courses - Course created ".$courseInfo['code']);
  1467. } else {
  1468. $this->logger->addError("Courses - Can't create course:".$row['title']);
  1469. }
  1470. } else {
  1471. // Update
  1472. $params = [
  1473. 'title' => $row['title'],
  1474. 'category_code' => $row['course_category'],
  1475. 'visibility' => $row['visibility'],
  1476. ];
  1477. $result = CourseManager::update_attributes(
  1478. $courseInfo['real_id'],
  1479. $params
  1480. );
  1481. $addTeacherToSession = isset($courseInfo['add_teachers_to_sessions_courses']) && !empty($courseInfo['add_teachers_to_sessions_courses']) ? true : false;
  1482. $teachers = $row['teachers'];
  1483. if (!is_array($teachers)) {
  1484. $teachers = [$teachers];
  1485. }
  1486. if ($addTeacherToSession) {
  1487. $this->logger->addInfo("Add teacher to all course sessions");
  1488. CourseManager::updateTeachers(
  1489. $courseInfo,
  1490. $row['teachers'],
  1491. false,
  1492. true,
  1493. false,
  1494. $teacherBackup,
  1495. $this->logger
  1496. );
  1497. } else {
  1498. CourseManager::updateTeachers(
  1499. $courseInfo,
  1500. $row['teachers'],
  1501. true,
  1502. false,
  1503. false,
  1504. $teacherBackup,
  1505. $this->logger
  1506. );
  1507. }
  1508. foreach ($teachers as $teacherId) {
  1509. if (isset($groupBackup['tutor'][$teacherId]) &&
  1510. isset($groupBackup['tutor'][$teacherId][$courseInfo['code']])
  1511. ) {
  1512. foreach ($groupBackup['tutor'][$teacherId][$courseInfo['code']] as $data) {
  1513. $groupInfo = GroupManager::get_group_properties($data['group_id']);
  1514. GroupManager::subscribe_tutors(
  1515. [$teacherId],
  1516. $groupInfo,
  1517. $data['c_id']
  1518. );
  1519. }
  1520. }
  1521. if (isset($groupBackup['user'][$teacherId]) &&
  1522. isset($groupBackup['user'][$teacherId][$courseInfo['code']]) &&
  1523. !empty($groupBackup['user'][$teacherId][$courseInfo['code']])
  1524. ) {
  1525. foreach ($groupBackup['user'][$teacherId][$courseInfo['code']] as $data) {
  1526. $groupInfo = GroupManager::get_group_properties($data['group_id']);
  1527. GroupManager::subscribe_users(
  1528. [$teacherId],
  1529. $groupInfo,
  1530. $data['c_id']
  1531. );
  1532. }
  1533. }
  1534. }
  1535. if ($result) {
  1536. $this->logger->addInfo("Courses - Course updated ".$courseInfo['code']);
  1537. } else {
  1538. $this->logger->addError("Courses - Course NOT updated ".$courseInfo['code']);
  1539. }
  1540. }
  1541. }
  1542. }
  1543. if ($moveFile) {
  1544. $this->moveFile($file);
  1545. }
  1546. }
  1547. /**
  1548. * Parse filename: encora_subsessionsextid-static_31082016.csv.
  1549. *
  1550. * @param string $file
  1551. */
  1552. private function importSubscribeUserToCourseSessionExtStatic($file, $moveFile = true)
  1553. {
  1554. $data = Import::csv_reader($file);
  1555. if (!empty($data)) {
  1556. $this->logger->addInfo(count($data)." records found.");
  1557. $userIdList = [];
  1558. foreach ($data as $row) {
  1559. $chamiloUserName = $row['UserName'];
  1560. $chamiloCourseCode = $row['CourseCode'];
  1561. $externalSessionId = $row['ExtSessionID'];
  1562. $status = $row['Status'];
  1563. $chamiloSessionId = null;
  1564. if (!empty($externalSessionId)) {
  1565. $chamiloSessionId = SessionManager::getSessionIdFromOriginalId(
  1566. $externalSessionId,
  1567. $this->extraFieldIdNameList['session']
  1568. );
  1569. }
  1570. $sessionInfo = api_get_session_info($chamiloSessionId);
  1571. if (empty($sessionInfo)) {
  1572. $this->logger->addError('Session does not exists: '.$chamiloSessionId);
  1573. continue;
  1574. }
  1575. $courseInfo = api_get_course_info($chamiloCourseCode);
  1576. if (empty($courseInfo)) {
  1577. $this->logger->addError('Course does not exists: '.$courseInfo);
  1578. continue;
  1579. }
  1580. $userId = UserManager::get_user_id_from_username($chamiloUserName);
  1581. if (empty($userId)) {
  1582. $this->logger->addError('User does not exists: '.$chamiloUserName);
  1583. continue;
  1584. }
  1585. switch ($status) {
  1586. case 'student':
  1587. SessionManager::subscribe_users_to_session_course(
  1588. [$userId],
  1589. $chamiloSessionId,
  1590. $courseInfo['code']
  1591. );
  1592. break;
  1593. case 'teacher':
  1594. SessionManager::set_coach_to_course_session(
  1595. $userId,
  1596. $chamiloSessionId,
  1597. $courseInfo['code']
  1598. );
  1599. break;
  1600. case 'drh':
  1601. $removeAllSessionsFromUser = true;
  1602. if (in_array($userId, $userIdList)) {
  1603. $removeAllSessionsFromUser = false;
  1604. } else {
  1605. $userIdList[] = $userId;
  1606. }
  1607. $userInfo = api_get_user_info($userId);
  1608. SessionManager::subscribeSessionsToDrh(
  1609. $userInfo,
  1610. [$chamiloSessionId],
  1611. false,
  1612. $removeAllSessionsFromUser
  1613. );
  1614. break;
  1615. }
  1616. $this->logger->addError(
  1617. "User '$chamiloUserName' was added as '$status' to Session: #$chamiloSessionId - Course: ".$courseInfo['code']
  1618. );
  1619. }
  1620. }
  1621. if ($moveFile) {
  1622. $this->moveFile($file);
  1623. }
  1624. }
  1625. /**
  1626. * @param $file
  1627. * @param bool $moveFile
  1628. */
  1629. private function importUnsubSessionsExtIdStatic($file, $moveFile = true)
  1630. {
  1631. $data = Import::csv_reader($file);
  1632. if (!empty($data)) {
  1633. $this->logger->addInfo(count($data)." records found.");
  1634. foreach ($data as $row) {
  1635. $chamiloUserName = $row['UserName'];
  1636. $chamiloCourseCode = $row['CourseCode'];
  1637. $externalSessionId = $row['ExtSessionID'];
  1638. $dateStop = $row['DateStop'];
  1639. $chamiloSessionId = null;
  1640. if (!empty($externalSessionId)) {
  1641. $chamiloSessionId = SessionManager::getSessionIdFromOriginalId(
  1642. $externalSessionId,
  1643. $this->extraFieldIdNameList['session']
  1644. );
  1645. }
  1646. $sessionInfo = api_get_session_info($chamiloSessionId);
  1647. if (empty($sessionInfo)) {
  1648. $this->logger->addError('Session does not exists: '.$chamiloSessionId);
  1649. continue;
  1650. }
  1651. $courseInfo = api_get_course_info($chamiloCourseCode);
  1652. if (empty($courseInfo)) {
  1653. $this->logger->addError('Course does not exists: '.$courseInfo);
  1654. continue;
  1655. }
  1656. $userId = UserManager::get_user_id_from_username($chamiloUserName);
  1657. if (empty($userId)) {
  1658. $this->logger->addError('User does not exists: '.$chamiloUserName);
  1659. continue;
  1660. }
  1661. SessionManager::removeUsersFromCourseSession(
  1662. [$userId],
  1663. $chamiloSessionId,
  1664. $courseInfo
  1665. );
  1666. $this->logger->addError(
  1667. "User '$chamiloUserName' was remove from Session: #$chamiloSessionId - Course: ".$courseInfo['code']
  1668. );
  1669. }
  1670. }
  1671. if ($moveFile) {
  1672. $this->moveFile($file);
  1673. }
  1674. }
  1675. /**
  1676. * @param string $file
  1677. */
  1678. private function importSessionsExtIdStatic($file, $moveFile = true)
  1679. {
  1680. $data = Import::csv_reader($file);
  1681. if (!empty($data)) {
  1682. $this->logger->addInfo(count($data)." records found.");
  1683. foreach ($data as $row) {
  1684. $chamiloUserName = $row['UserName'];
  1685. $chamiloCourseCode = $row['CourseCode'];
  1686. $externalSessionId = $row['ExtSessionID'];
  1687. $type = $row['Type'];
  1688. $chamiloSessionId = null;
  1689. if (!empty($externalSessionId)) {
  1690. $chamiloSessionId = SessionManager::getSessionIdFromOriginalId(
  1691. $externalSessionId,
  1692. $this->extraFieldIdNameList['session']
  1693. );
  1694. }
  1695. $sessionInfo = api_get_session_info($chamiloSessionId);
  1696. if (empty($sessionInfo)) {
  1697. $this->logger->addError('Session does not exists: '.$chamiloSessionId);
  1698. continue;
  1699. }
  1700. $courseInfo = api_get_course_info($chamiloCourseCode);
  1701. if (empty($courseInfo)) {
  1702. $this->logger->addError('Course does not exists: '.$courseInfo);
  1703. continue;
  1704. }
  1705. $userId = UserManager::get_user_id_from_username($chamiloUserName);
  1706. if (empty($userId)) {
  1707. $this->logger->addError('User does not exists: '.$chamiloUserName);
  1708. continue;
  1709. }
  1710. switch ($type) {
  1711. case 'student':
  1712. SessionManager::subscribe_users_to_session_course(
  1713. [$userId],
  1714. $chamiloSessionId,
  1715. $courseInfo['code'],
  1716. null,
  1717. false
  1718. );
  1719. break;
  1720. case 'teacher':
  1721. SessionManager::set_coach_to_course_session(
  1722. $userId,
  1723. $chamiloSessionId,
  1724. $courseInfo['code']
  1725. );
  1726. break;
  1727. }
  1728. $this->logger->addError(
  1729. "User '$chamiloUserName' with status $type was added to session: #$chamiloSessionId - Course: ".$courseInfo['code']
  1730. );
  1731. }
  1732. }
  1733. if ($moveFile) {
  1734. $this->moveFile($file);
  1735. }
  1736. }
  1737. /**
  1738. * Updates the session synchronize with the csv file.
  1739. *
  1740. * @param bool $moveFile
  1741. * @param string $file
  1742. */
  1743. private function importSessionsStatic($file, $moveFile = true)
  1744. {
  1745. $content = file($file);
  1746. $sessions = [];
  1747. $tag_names = [];
  1748. foreach ($content as $key => $enreg) {
  1749. $enreg = explode(';', trim($enreg));
  1750. if ($key) {
  1751. foreach ($tag_names as $tag_key => $tag_name) {
  1752. if (isset($enreg[$tag_key])) {
  1753. $sessions[$key - 1][$tag_name] = $enreg[$tag_key];
  1754. }
  1755. }
  1756. } else {
  1757. foreach ($enreg as $tag_name) {
  1758. $tag_names[] = api_preg_replace(
  1759. '/[^a-zA-Z0-9_\-]/',
  1760. '',
  1761. $tag_name
  1762. );
  1763. }
  1764. if (!in_array('SessionName', $tag_names) ||
  1765. !in_array('DateStart', $tag_names) || !in_array('DateEnd', $tag_names)
  1766. ) {
  1767. $error_message = get_lang('NoNeededData');
  1768. break;
  1769. }
  1770. }
  1771. }
  1772. if (!empty($sessions)) {
  1773. // Looping the sessions.
  1774. foreach ($sessions as $session) {
  1775. if (!empty($session['SessionID'])) {
  1776. $sessionId = SessionManager::getSessionIdFromOriginalId(
  1777. $session['SessionID'],
  1778. $this->extraFieldIdNameList['session']
  1779. );
  1780. $coachUserName = isset($session['Coach']) ? $session['Coach'] : null;
  1781. $categoryId = isset($session['category_id']) ? $session['category_id'] : null;
  1782. // 2014-06-30
  1783. $dateStart = explode('/', $session['DateStart']);
  1784. $dateEnd = explode('/', $session['DateEnd']);
  1785. $visibility = $this->defaultSessionVisibility;
  1786. $coachId = null;
  1787. if (!empty($coachUserName)) {
  1788. $coachInfo = api_get_user_info_from_username($coachUserName);
  1789. $coachId = $coachInfo['user_id'];
  1790. }
  1791. $dateStart = $dateStart[0].'-'.$dateStart[1].'-'.$dateStart[2].' 00:00:00';
  1792. $dateEnd = $dateEnd[0].'-'.$dateEnd[1].'-'.$dateEnd[2].' 23:59:59';
  1793. $date = new \DateTime($dateStart);
  1794. $interval = new DateInterval('P'.$this->daysCoachAccessBeforeBeginning.'D');
  1795. $date->sub($interval);
  1796. $coachBefore = $date->format('Y-m-d h:i');
  1797. $date = new \DateTime($dateEnd);
  1798. $interval = new DateInterval('P'.$this->daysCoachAccessAfterBeginning.'D');
  1799. $date->add($interval);
  1800. $coachAfter = $date->format('Y-m-d h:i');
  1801. /*$dateStart = api_get_utc_datetime($dateStart);
  1802. $dateEnd = api_get_utc_datetime($dateEnd);
  1803. $coachBefore = api_get_utc_datetime($coachBefore);
  1804. $coachAfter = api_get_utc_datetime($coachAfter);*/
  1805. if (empty($sessionId)) {
  1806. $result = SessionManager::create_session(
  1807. $session['SessionName'],
  1808. $dateStart,
  1809. $dateEnd,
  1810. $dateStart,
  1811. $dateEnd,
  1812. $coachBefore,
  1813. $coachAfter,
  1814. $coachId,
  1815. $categoryId,
  1816. $visibility
  1817. );
  1818. if (is_numeric($result)) {
  1819. $sessionId = $result;
  1820. $this->logger->addInfo("Session #$sessionId created: ".$session['SessionName']);
  1821. SessionManager::update_session_extra_field_value(
  1822. $sessionId,
  1823. $this->extraFieldIdNameList['session'],
  1824. $session['SessionID']
  1825. );
  1826. } else {
  1827. $this->logger->addInfo("Failed creating session: ".$session['SessionName']);
  1828. }
  1829. } else {
  1830. $sessionInfo = api_get_session_info($sessionId);
  1831. $accessBefore = null;
  1832. $accessAfter = null;
  1833. if (empty($sessionInfo['nb_days_access_before_beginning']) ||
  1834. (!empty($sessionInfo['nb_days_access_before_beginning']) &&
  1835. $sessionInfo['nb_days_access_before_beginning'] < $this->daysCoachAccessBeforeBeginning)
  1836. ) {
  1837. $accessBefore = $coachBefore;
  1838. }
  1839. $accessAfter = null;
  1840. if (empty($sessionInfo['nb_days_access_after_end']) ||
  1841. (!empty($sessionInfo['nb_days_access_after_end']) &&
  1842. $sessionInfo['nb_days_access_after_end'] < $this->daysCoachAccessAfterBeginning)
  1843. ) {
  1844. $accessAfter = $coachAfter;
  1845. }
  1846. $showDescription = isset($sessionInfo['show_description']) ? $sessionInfo['show_description'] : 1;
  1847. $result = SessionManager::edit_session(
  1848. $sessionId,
  1849. $session['SessionName'],
  1850. $dateStart,
  1851. $dateEnd,
  1852. $dateStart,
  1853. $dateEnd,
  1854. $accessBefore,
  1855. $accessAfter,
  1856. $coachId,
  1857. $categoryId,
  1858. $visibility,
  1859. null, //$description = null,
  1860. $showDescription
  1861. );
  1862. if (is_numeric($result)) {
  1863. $this->logger->addInfo("Session #$sessionId updated: ".$session['SessionName']);
  1864. $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
  1865. $params = [
  1866. 'description' => $session['SessionDescription'],
  1867. ];
  1868. Database::update(
  1869. $tbl_session,
  1870. $params,
  1871. ['id = ?' => $sessionId]
  1872. );
  1873. }
  1874. }
  1875. if (!empty($sessionId)) {
  1876. // Courses
  1877. $courses = explode('|', $session['Courses']);
  1878. $courseList = [];
  1879. $courseListWithCoach = [];
  1880. foreach ($courses as $course) {
  1881. $courseArray = bracketsToArray($course);
  1882. $courseCode = $courseArray[0];
  1883. if (CourseManager::course_exists($courseCode)) {
  1884. $courseInfo = api_get_course_info($courseCode);
  1885. $courseList[] = $courseInfo['real_id'];
  1886. // Extracting course coaches
  1887. $courseCoaches = isset($courseArray[1]) ? $courseArray[1] : null;
  1888. $courseCoaches = explode(',', $courseCoaches);
  1889. // Extracting students
  1890. $courseUsers = isset($courseArray[2]) ? $courseArray[2] : null;
  1891. $courseUsers = explode(',', $courseUsers);
  1892. $courseListWithCoach[] = [
  1893. 'course_info' => $courseInfo,
  1894. 'coaches' => $courseCoaches,
  1895. 'course_users' => $courseUsers,
  1896. ];
  1897. }
  1898. }
  1899. SessionManager::add_courses_to_session(
  1900. $sessionId,
  1901. $courseList,
  1902. true
  1903. );
  1904. $this->logger->addInfo("Session #$sessionId: Courses added: '".implode(', ', $courseList)."'");
  1905. if (empty($courseListWithCoach)) {
  1906. $this->logger->addInfo("No users/coaches to update");
  1907. continue;
  1908. }
  1909. foreach ($courseListWithCoach as $courseData) {
  1910. $courseInfo = $courseData['course_info'];
  1911. $courseCode = $courseInfo['code'];
  1912. $courseId = $courseInfo['real_id'];
  1913. $courseCoaches = $courseData['coaches'];
  1914. $courseUsers = $courseData['course_users'];
  1915. // Coaches
  1916. if (!empty($courseCoaches)) {
  1917. $coachList = [];
  1918. foreach ($courseCoaches as $courseCoach) {
  1919. $courseCoachId = UserManager::get_user_id_from_username(
  1920. $courseCoach
  1921. );
  1922. if ($courseCoachId !== false) {
  1923. // Just insert new coaches
  1924. $coachList[] = $courseCoachId;
  1925. }
  1926. }
  1927. $this->logger->addInfo("Session #$sessionId: course '$courseCode' coaches added: '".implode(', ', $coachList)."'");
  1928. SessionManager::updateCoaches(
  1929. $sessionId,
  1930. $courseId,
  1931. $coachList,
  1932. true
  1933. );
  1934. } else {
  1935. $this->logger->addInfo("No coaches added");
  1936. }
  1937. // Students
  1938. if (!empty($courseUsers)) {
  1939. $userList = [];
  1940. foreach ($courseUsers as $username) {
  1941. $userInfo = api_get_user_info_from_username(trim($username));
  1942. if (!empty($userInfo)) {
  1943. $userList[] = $userInfo['user_id'];
  1944. }
  1945. }
  1946. $this->logger->addInfo("Session #$sessionId: course '$courseCode': Students added '".implode(', ', $userList)."'");
  1947. SessionManager::subscribe_users_to_session_course(
  1948. $userList,
  1949. $sessionId,
  1950. $courseCode,
  1951. SESSION_VISIBLE_READ_ONLY,
  1952. true
  1953. );
  1954. } else {
  1955. $this->logger->addInfo("No users to register.");
  1956. }
  1957. }
  1958. } else {
  1959. $this->logger->addInfo(
  1960. 'SessionID not found in system.'
  1961. );
  1962. }
  1963. } else {
  1964. $this->logger->addInfo('SessionID does not exists');
  1965. }
  1966. }
  1967. } else {
  1968. $this->logger->addInfo($error_message);
  1969. }
  1970. if ($moveFile) {
  1971. $this->moveFile($file);
  1972. }
  1973. }
  1974. /**
  1975. * @param $file
  1976. * @param bool $moveFile
  1977. * @param array $teacherBackup
  1978. * @param array $groupBackup
  1979. */
  1980. private function importOpenSessions(
  1981. $file,
  1982. $moveFile = true,
  1983. &$teacherBackup = [],
  1984. &$groupBackup = []
  1985. ) {
  1986. $this->importSessions($file, $moveFile, $teacherBackup, $groupBackup);
  1987. }
  1988. /**
  1989. * @param string $file
  1990. * @param bool $moveFile
  1991. * @param array $teacherBackup
  1992. * @param array $groupBackup
  1993. */
  1994. private function importSessions(
  1995. $file,
  1996. $moveFile = true,
  1997. &$teacherBackup = [],
  1998. &$groupBackup = []
  1999. ) {
  2000. $avoid = null;
  2001. if (isset($this->conditions['importSessions']) &&
  2002. isset($this->conditions['importSessions']['update'])
  2003. ) {
  2004. $avoid = $this->conditions['importSessions']['update'];
  2005. }
  2006. $result = SessionManager::importCSV(
  2007. $file,
  2008. true,
  2009. $this->defaultAdminId,
  2010. $this->logger,
  2011. [
  2012. 'SessionID' => 'extra_'.$this->extraFieldIdNameList['session'],
  2013. 'CareerId' => 'extra_'.$this->extraFieldIdNameList['session_career'],
  2014. ],
  2015. $this->extraFieldIdNameList['session'],
  2016. $this->daysCoachAccessBeforeBeginning,
  2017. $this->daysCoachAccessAfterBeginning,
  2018. $this->defaultSessionVisibility,
  2019. $avoid,
  2020. false, // deleteUsersNotInList
  2021. false, // updateCourseCoaches
  2022. true, // sessionWithCoursesModifier
  2023. true, //$addOriginalCourseTeachersAsCourseSessionCoaches
  2024. false, //$removeAllTeachersFromCourse
  2025. 1, // $showDescription,
  2026. $teacherBackup,
  2027. $groupBackup
  2028. );
  2029. if (!empty($result['error_message'])) {
  2030. $this->logger->addError($result['error_message']);
  2031. }
  2032. $this->logger->addInfo("Sessions - Sessions parsed: ".$result['session_counter']);
  2033. if ($moveFile) {
  2034. $this->moveFile($file);
  2035. }
  2036. }
  2037. /**
  2038. * @param string $file
  2039. * @param bool $moveFile
  2040. */
  2041. private function importSubscribeStatic($file, $moveFile = true)
  2042. {
  2043. $data = Import::csv_reader($file);
  2044. if (!empty($data)) {
  2045. $this->logger->addInfo(count($data)." records found.");
  2046. foreach ($data as $row) {
  2047. $chamiloUserName = $row['UserName'];
  2048. $chamiloCourseCode = $row['CourseCode'];
  2049. $chamiloSessionId = $row['SessionID'];
  2050. $type = $row['Type'];
  2051. $sessionInfo = api_get_session_info($chamiloSessionId);
  2052. if (empty($sessionInfo)) {
  2053. $this->logger->addError('Session does not exists: '.$chamiloSessionId);
  2054. continue;
  2055. }
  2056. $courseInfo = api_get_course_info($chamiloCourseCode);
  2057. if (empty($courseInfo)) {
  2058. $this->logger->addError('Course does not exists: '.$courseInfo);
  2059. continue;
  2060. }
  2061. $userId = UserManager::get_user_id_from_username($chamiloUserName);
  2062. if (empty($userId)) {
  2063. $this->logger->addError('User does not exists: '.$chamiloUserName);
  2064. continue;
  2065. }
  2066. switch ($type) {
  2067. case 'student':
  2068. SessionManager::subscribe_users_to_session_course(
  2069. [$userId],
  2070. $chamiloSessionId,
  2071. $courseInfo['code'],
  2072. null,
  2073. false
  2074. );
  2075. break;
  2076. case 'teacher':
  2077. SessionManager::set_coach_to_course_session(
  2078. $userId,
  2079. $chamiloSessionId,
  2080. $courseInfo['real_id']
  2081. );
  2082. break;
  2083. }
  2084. $this->logger->addError(
  2085. "User '$chamiloUserName' with status $type was added to session: #$chamiloSessionId - Course: ".$courseInfo['code']
  2086. );
  2087. }
  2088. }
  2089. if ($moveFile) {
  2090. $this->moveFile($file);
  2091. }
  2092. }
  2093. /**
  2094. * @param $file
  2095. * @param bool $moveFile
  2096. */
  2097. private function importSubscribeUserToCourse($file, $moveFile = false, &$teacherBackup = [])
  2098. {
  2099. $data = Import::csv_reader($file);
  2100. if (!empty($data)) {
  2101. $this->logger->addInfo(count($data)." records found.");
  2102. foreach ($data as $row) {
  2103. $chamiloUserName = $row['UserName'];
  2104. $chamiloCourseCode = $row['CourseCode'];
  2105. $status = $row['Status'];
  2106. $courseInfo = api_get_course_info($chamiloCourseCode);
  2107. if (empty($courseInfo)) {
  2108. $this->logger->addError(
  2109. 'Course does not exists: '.$chamiloCourseCode
  2110. );
  2111. continue;
  2112. }
  2113. $userId = UserManager::get_user_id_from_username(
  2114. $chamiloUserName
  2115. );
  2116. if (empty($userId)) {
  2117. $this->logger->addError(
  2118. 'User does not exists: '.$chamiloUserName
  2119. );
  2120. continue;
  2121. }
  2122. $userCourseCategory = '';
  2123. if (isset($teacherBackup[$userId]) &&
  2124. isset($teacherBackup[$userId][$courseInfo['code']])
  2125. ) {
  2126. $courseUserData = $teacherBackup[$userId][$courseInfo['code']];
  2127. $userCourseCategory = $courseUserData['user_course_cat'];
  2128. }
  2129. $result = CourseManager::subscribeUser(
  2130. $userId,
  2131. $courseInfo['code'],
  2132. $status,
  2133. 0,
  2134. $userCourseCategory
  2135. );
  2136. if ($result) {
  2137. $this->logger->addInfo(
  2138. "User $userId added to course ".$courseInfo['code']." with status '$status' with course category: '$userCourseCategory'"
  2139. );
  2140. } else {
  2141. $this->logger->addInfo(
  2142. "User $userId was NOT ADDED to course ".$courseInfo['code']." with status '$status' with course category: '$userCourseCategory'"
  2143. );
  2144. }
  2145. }
  2146. }
  2147. if ($moveFile) {
  2148. $this->moveFile($file);
  2149. }
  2150. }
  2151. /**
  2152. * 23/4/2017 to datetime.
  2153. *
  2154. * @param $string
  2155. *
  2156. * @return mixed
  2157. */
  2158. private function createDateTime($string)
  2159. {
  2160. if (empty($string)) {
  2161. return null;
  2162. }
  2163. $date = DateTime::createFromFormat('j/m/Y', $string);
  2164. if ($date) {
  2165. return $date;
  2166. }
  2167. return null;
  2168. }
  2169. /**
  2170. * @param $file
  2171. * @param bool $moveFile
  2172. * @param array $teacherBackup
  2173. * @param array $groupBackup
  2174. *
  2175. * @return bool
  2176. */
  2177. private function importCareers(
  2178. $file,
  2179. $moveFile = false,
  2180. &$teacherBackup = [],
  2181. &$groupBackup = []
  2182. ) {
  2183. $data = Import::csv_reader($file);
  2184. if (!empty($data)) {
  2185. $this->logger->addInfo(count($data)." records found.");
  2186. $extraFieldValue = new ExtraFieldValue('career');
  2187. $extraFieldName = $this->extraFieldIdNameList['career'];
  2188. $externalEventId = null;
  2189. $extraField = new ExtraField('career');
  2190. $extraFieldInfo = $extraField->get_handler_field_info_by_field_variable(
  2191. $extraFieldName
  2192. );
  2193. if (empty($extraFieldInfo)) {
  2194. return false;
  2195. }
  2196. foreach ($data as $row) {
  2197. foreach ($row as $key => $value) {
  2198. $key = (string) trim($key);
  2199. // Remove utf8 bom
  2200. $key = preg_replace('/[\x00-\x1F\x80-\xFF]/', '', $key);
  2201. $row[$key] = $value;
  2202. }
  2203. $itemId = $row['CareerId'];
  2204. $item = $extraFieldValue->get_item_id_from_field_variable_and_field_value(
  2205. $extraFieldName,
  2206. $itemId,
  2207. false,
  2208. false,
  2209. false
  2210. );
  2211. $career = new Career();
  2212. if (empty($item)) {
  2213. $params = [
  2214. 'status' => 1,
  2215. 'name' => $row['CareerName'],
  2216. ];
  2217. $careerId = $career->save($params);
  2218. if ($careerId) {
  2219. $params = [
  2220. 'item_id' => $careerId,
  2221. 'extra_'.$extraFieldName => $itemId,
  2222. ];
  2223. $links = isset($row['HLinks']) ? $row['HLinks'] : [];
  2224. if (!empty($links)) {
  2225. $extraFieldUrlName = $this->extraFieldIdNameList['career_urls'];
  2226. $extraFieldInfo = $extraField->get_handler_field_info_by_field_variable(
  2227. $extraFieldUrlName
  2228. );
  2229. if (!empty($extraFieldInfo)) {
  2230. $params['extra_'.$extraFieldUrlName] = $links;
  2231. }
  2232. }
  2233. $extraFieldValue->saveFieldValues($params);
  2234. }
  2235. } else {
  2236. if (isset($item['item_id'])) {
  2237. $params = [
  2238. 'id' => $item['item_id'],
  2239. 'name' => $row['CareerName'],
  2240. ];
  2241. $career->update($params);
  2242. $links = isset($row['HLinks']) ? $row['HLinks'] : [];
  2243. if (!empty($links)) {
  2244. $extraFieldUrlName = $this->extraFieldIdNameList['career_urls'];
  2245. $extraFieldInfo = $extraField->get_handler_field_info_by_field_variable(
  2246. $extraFieldUrlName
  2247. );
  2248. if (!empty($extraFieldInfo)) {
  2249. $params = [
  2250. 'item_id' => $item['item_id'],
  2251. 'extra_'.$extraFieldName => $itemId,
  2252. 'extra_'.$extraFieldUrlName => $links,
  2253. ];
  2254. $extraFieldValue->saveFieldValues($params);
  2255. }
  2256. }
  2257. }
  2258. }
  2259. }
  2260. }
  2261. }
  2262. /**
  2263. * @param $file
  2264. * @param bool $moveFile
  2265. * @param array $teacherBackup
  2266. * @param array $groupBackup
  2267. */
  2268. private function importCareersDiagram(
  2269. $file,
  2270. $moveFile = false,
  2271. &$teacherBackup = [],
  2272. &$groupBackup = []
  2273. ) {
  2274. $data = Import::csv_reader($file);
  2275. $extraFieldValue = new ExtraFieldValue('career');
  2276. $extraFieldName = $this->extraFieldIdNameList['career'];
  2277. $externalEventId = null;
  2278. $extraField = new ExtraField('career');
  2279. $extraFieldInfo = $extraField->get_handler_field_info_by_field_variable(
  2280. $extraFieldName
  2281. );
  2282. $careerDiagramExtraFieldName = $this->extraFieldIdNameList['career_diagram'];
  2283. $extraFieldDiagramInfo = $extraField->get_handler_field_info_by_field_variable(
  2284. $careerDiagramExtraFieldName
  2285. );
  2286. if (empty($extraFieldInfo) || empty($extraFieldDiagramInfo)) {
  2287. return false;
  2288. }
  2289. if (!empty($data)) {
  2290. $this->logger->addInfo(count($data)." records found.");
  2291. $values = [];
  2292. foreach ($data as $row) {
  2293. if (empty($row)) {
  2294. continue;
  2295. }
  2296. foreach ($row as $key => $value) {
  2297. $key = (string) trim($key);
  2298. // Remove utf8 bom
  2299. $key = preg_replace('/[\x00-\x1F\x80-\xFF]/', '', $key);
  2300. $row[$key] = $value;
  2301. }
  2302. $values[$row['Column']][] = $row;
  2303. }
  2304. $careerList = [];
  2305. $careerNameList = [];
  2306. ksort($values);
  2307. $careerChamiloIdList = [];
  2308. // 1. First create all items
  2309. foreach ($values as $column => $rowList) {
  2310. foreach ($rowList as $row) {
  2311. $careerId = $row['CareerId'];
  2312. $item = $extraFieldValue->get_item_id_from_field_variable_and_field_value(
  2313. $extraFieldName,
  2314. $careerId,
  2315. false,
  2316. false,
  2317. false
  2318. );
  2319. $chamiloCareerName = '';
  2320. if (empty($item)) {
  2321. $this->logger->addInfo("Career not found: $careerId");
  2322. continue;
  2323. } else {
  2324. if (isset($item['item_id'])) {
  2325. $careerChamiloId = $item['item_id'];
  2326. $career = new Career();
  2327. $career = $career->find($careerChamiloId);
  2328. $chamiloCareerName = $career['name'];
  2329. $careerNameList[$careerId] = $chamiloCareerName;
  2330. $careerChamiloIdList[$careerId] = $careerChamiloId;
  2331. } else {
  2332. continue;
  2333. }
  2334. }
  2335. if (empty($chamiloCareerName)) {
  2336. $this->logger->addInfo("Career not found: $careerId");
  2337. continue;
  2338. }
  2339. if (isset($careerList[$careerId])) {
  2340. $graph = $careerList[$careerId];
  2341. } else {
  2342. $graph = new Graph($careerId);
  2343. $graph->setAttribute('graphviz.graph.rankdir', 'LR');
  2344. $careerList[$careerId] = $graph;
  2345. }
  2346. $currentCourseId = (int) $row['CourseId'];
  2347. $name = $row['CourseName'];
  2348. $notes = $row['Notes'];
  2349. $groupValue = $row['Group'];
  2350. $boxColumn = $row['Column'];
  2351. $rowValue = $row['Row'];
  2352. $color = isset($row['DefinedColor']) ? $row['DefinedColor'] : '';
  2353. $arrow = isset($row['DrawArrowFrom']) ? $row['DrawArrowFrom'] : '';
  2354. $subGroup = isset($row['SubGroup']) ? $row['SubGroup'] : '';
  2355. $connections = isset($row['Connections']) ? $row['Connections'] : '';
  2356. $linkedElement = isset($row['LinkedElement']) ? $row['LinkedElement'] : '';
  2357. if ($graph->hasVertex($currentCourseId)) {
  2358. // Avoid double insertion
  2359. continue;
  2360. } else {
  2361. $current = $graph->createVertex($currentCourseId);
  2362. $current->setAttribute('graphviz.label', $name);
  2363. $current->setAttribute('DefinedColor', $color);
  2364. $current->setAttribute('Notes', $notes);
  2365. $current->setAttribute('Row', $rowValue);
  2366. $current->setAttribute('Group', $groupValue);
  2367. $current->setAttribute('Column', $boxColumn);
  2368. $current->setAttribute('DrawArrowFrom', $arrow);
  2369. $current->setAttribute('SubGroup', $subGroup);
  2370. $current->setAttribute('Connections', $connections);
  2371. $current->setAttribute('LinkedElement', $linkedElement);
  2372. $current->setAttribute('graphviz.shape', 'box');
  2373. $current->setGroup($column);
  2374. }
  2375. }
  2376. }
  2377. // 2. Create connections
  2378. // $column start with 1 (depending in Column row)
  2379. foreach ($values as $column => $rowList) {
  2380. foreach ($rowList as $row) {
  2381. $careerId = $row['CareerId'];
  2382. if (isset($careerList[$careerId])) {
  2383. $graph = $careerList[$careerId];
  2384. } else {
  2385. continue;
  2386. }
  2387. $currentCourseId = (int) $row['CourseId'];
  2388. if ($graph->hasVertex($currentCourseId)) {
  2389. $current = $graph->getVertex($currentCourseId);
  2390. } else {
  2391. continue;
  2392. }
  2393. if (isset($row['DependedOn']) && !empty($row['DependedOn'])) {
  2394. $parentList = explode(',', $row['DependedOn']);
  2395. foreach ($parentList as $parentId) {
  2396. $parentId = (int) $parentId;
  2397. if ($graph->hasVertex($parentId)) {
  2398. /** @var Vertex $parent */
  2399. $parent = $graph->getVertex($parentId);
  2400. /*$parent->setAttribute('graphviz.color', 'red');
  2401. $parent->setAttribute('graphviz.label', $name);
  2402. $parent->setAttribute('graphviz.shape', 'square');*/
  2403. $parent->createEdgeTo($current);
  2404. }
  2405. }
  2406. }
  2407. }
  2408. }
  2409. /** @var Graph $graph */
  2410. foreach ($careerList as $id => $graph) {
  2411. if (isset($careerChamiloIdList[$id])) {
  2412. $params = [
  2413. 'item_id' => $careerChamiloIdList[$id],
  2414. 'extra_'.$careerDiagramExtraFieldName => serialize($graph),
  2415. 'extra_'.$extraFieldName => $id,
  2416. ];
  2417. $extraFieldValue->saveFieldValues($params, true);
  2418. }
  2419. }
  2420. }
  2421. }
  2422. /**
  2423. * @param string $file
  2424. * @param bool $moveFile
  2425. * @param array $teacherBackup
  2426. * @param array $groupBackup
  2427. */
  2428. private function importUnsubscribeStatic(
  2429. $file,
  2430. $moveFile = false,
  2431. &$teacherBackup = [],
  2432. &$groupBackup = []
  2433. ) {
  2434. $data = Import::csv_reader($file);
  2435. if (!empty($data)) {
  2436. $this->logger->addInfo(count($data)." records found.");
  2437. foreach ($data as $row) {
  2438. $chamiloUserName = $row['UserName'];
  2439. $chamiloCourseCode = $row['CourseCode'];
  2440. $chamiloSessionId = $row['SessionID'];
  2441. $sessionInfo = api_get_session_info($chamiloSessionId);
  2442. if (empty($sessionInfo)) {
  2443. $this->logger->addError('Session does not exists: '.$chamiloSessionId);
  2444. continue;
  2445. }
  2446. $courseInfo = api_get_course_info($chamiloCourseCode);
  2447. if (empty($courseInfo)) {
  2448. $this->logger->addError('Course does not exists: '.$courseInfo);
  2449. continue;
  2450. }
  2451. $userId = UserManager::get_user_id_from_username($chamiloUserName);
  2452. if (empty($userId)) {
  2453. $this->logger->addError('User does not exists: '.$chamiloUserName);
  2454. continue;
  2455. }
  2456. $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)."
  2457. WHERE
  2458. user_id = ".$userId." AND
  2459. c_id = '".$courseInfo['real_id']."'
  2460. ";
  2461. $result = Database::query($sql);
  2462. $rows = Database::num_rows($result);
  2463. if ($rows > 0) {
  2464. $userCourseData = Database::fetch_array($result, 'ASSOC');
  2465. if (!empty($userCourseData)) {
  2466. $teacherBackup[$userId][$courseInfo['code']] = $userCourseData;
  2467. }
  2468. }
  2469. $sql = "SELECT * FROM ".Database::get_course_table(TABLE_GROUP_USER)."
  2470. WHERE
  2471. user_id = ".$userId." AND
  2472. c_id = '".$courseInfo['real_id']."'
  2473. ";
  2474. $result = Database::query($sql);
  2475. while ($groupData = Database::fetch_array($result, 'ASSOC')) {
  2476. $groupBackup['user'][$userId][$courseInfo['code']][$groupData['group_id']] = $groupData;
  2477. }
  2478. $sql = "SELECT * FROM ".Database::get_course_table(TABLE_GROUP_TUTOR)."
  2479. WHERE
  2480. user_id = ".$userId." AND
  2481. c_id = '".$courseInfo['real_id']."'
  2482. ";
  2483. $result = Database::query($sql);
  2484. while ($groupData = Database::fetch_array($result, 'ASSOC')) {
  2485. $groupBackup['tutor'][$userId][$courseInfo['code']][$groupData['group_id']] = $groupData;
  2486. }
  2487. CourseManager::unsubscribe_user(
  2488. $userId,
  2489. $courseInfo['code'],
  2490. $chamiloSessionId
  2491. );
  2492. $this->logger->addError(
  2493. "User '$chamiloUserName' was removed from session: #$chamiloSessionId, Course: ".$courseInfo['code']
  2494. );
  2495. }
  2496. }
  2497. if ($moveFile) {
  2498. $this->moveFile($file);
  2499. }
  2500. }
  2501. /**
  2502. * Dump database tables.
  2503. */
  2504. private function dumpDatabaseTables()
  2505. {
  2506. echo 'Dumping tables'.PHP_EOL;
  2507. // User
  2508. $table = Database::get_main_table(TABLE_MAIN_USER);
  2509. $tableAdmin = Database::get_main_table(TABLE_MAIN_ADMIN);
  2510. $sql = "DELETE FROM $table
  2511. WHERE user_id not in (select user_id from $tableAdmin) and status <> ".ANONYMOUS;
  2512. Database::query($sql);
  2513. echo $sql.PHP_EOL;
  2514. // Truncate tables
  2515. $truncateTables = [
  2516. Database::get_main_table(TABLE_MAIN_COURSE),
  2517. Database::get_main_table(TABLE_MAIN_COURSE_USER),
  2518. Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE),
  2519. Database::get_main_table(TABLE_MAIN_CATEGORY),
  2520. Database::get_main_table(TABLE_MAIN_COURSE_MODULE),
  2521. Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER),
  2522. Database::get_main_table(TABLE_MAIN_SESSION),
  2523. Database::get_main_table(TABLE_MAIN_SESSION_CATEGORY),
  2524. Database::get_main_table(TABLE_MAIN_SESSION_COURSE),
  2525. Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER),
  2526. Database::get_main_table(TABLE_MAIN_SESSION_USER),
  2527. Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_SESSION),
  2528. Database::get_main_table(TABLE_MAIN_SESSION_FIELD_VALUES),
  2529. Database::get_main_table(TABLE_MAIN_COURSE_FIELD_VALUES),
  2530. Database::get_main_table(TABLE_MAIN_USER_FIELD_VALUES),
  2531. Database::get_main_table(TABLE_MAIN_USER_FIELD),
  2532. Database::get_main_table(TABLE_MAIN_USER_FIELD_OPTIONS),
  2533. Database::get_main_table(TABLE_MAIN_COURSE_FIELD),
  2534. Database::get_main_table(TABLE_MAIN_COURSE_FIELD_VALUES),
  2535. Database::get_main_table(TABLE_MAIN_SESSION_FIELD),
  2536. Database::get_main_table(TABLE_MAIN_SESSION_FIELD_VALUES),
  2537. Database::get_course_table(TABLE_AGENDA),
  2538. Database::get_course_table(TABLE_AGENDA_ATTACHMENT),
  2539. Database::get_course_table(TABLE_AGENDA_REPEAT),
  2540. Database::get_course_table(TABLE_AGENDA_REPEAT_NOT),
  2541. Database::get_main_table(TABLE_PERSONAL_AGENDA),
  2542. Database::get_main_table(TABLE_PERSONAL_AGENDA_REPEAT_NOT),
  2543. Database::get_main_table(TABLE_PERSONAL_AGENDA_REPEAT),
  2544. Database::get_main_table(TABLE_MAIN_CALENDAR_EVENT_VALUES),
  2545. Database::get_main_table(TABLE_STATISTIC_TRACK_E_LASTACCESS),
  2546. Database::get_main_table(TABLE_STATISTIC_TRACK_E_ACCESS),
  2547. Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN),
  2548. Database::get_main_table(TABLE_STATISTIC_TRACK_E_DOWNLOADS),
  2549. Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCICES),
  2550. Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT),
  2551. Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT_RECORDING),
  2552. Database::get_main_table(TABLE_STATISTIC_TRACK_E_DEFAULT),
  2553. Database::get_main_table(TABLE_STATISTIC_TRACK_E_UPLOADS),
  2554. Database::get_main_table(TABLE_STATISTIC_TRACK_E_HOTSPOT),
  2555. Database::get_main_table(TABLE_STATISTIC_TRACK_E_ITEM_PROPERTY),
  2556. Database::get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY),
  2557. Database::get_main_table(TABLE_MAIN_GRADEBOOK_EVALUATION),
  2558. Database::get_main_table(TABLE_MAIN_GRADEBOOK_LINKEVAL_LOG),
  2559. Database::get_main_table(TABLE_MAIN_GRADEBOOK_RESULT),
  2560. Database::get_main_table(TABLE_MAIN_GRADEBOOK_RESULT_LOG),
  2561. Database::get_main_table(TABLE_MAIN_GRADEBOOK_LINK),
  2562. Database::get_main_table(TABLE_MAIN_GRADEBOOK_SCORE_DISPLAY),
  2563. Database::get_main_table(TABLE_MAIN_GRADEBOOK_CERTIFICATE),
  2564. Database::get_course_table(TABLE_STUDENT_PUBLICATION),
  2565. Database::get_course_table(TABLE_QUIZ_QUESTION),
  2566. Database::get_course_table(TABLE_QUIZ_TEST),
  2567. Database::get_course_table(TABLE_QUIZ_ORDER),
  2568. Database::get_course_table(TABLE_QUIZ_ANSWER),
  2569. Database::get_course_table(TABLE_QUIZ_TEST_QUESTION),
  2570. Database::get_course_table(TABLE_QUIZ_QUESTION_OPTION),
  2571. Database::get_course_table(TABLE_QUIZ_QUESTION_CATEGORY),
  2572. Database::get_course_table(TABLE_QUIZ_QUESTION_REL_CATEGORY),
  2573. Database::get_course_table(TABLE_LP_MAIN),
  2574. Database::get_course_table(TABLE_LP_ITEM),
  2575. Database::get_course_table(TABLE_LP_VIEW),
  2576. Database::get_course_table(TABLE_LP_ITEM_VIEW),
  2577. Database::get_course_table(TABLE_DOCUMENT),
  2578. Database::get_course_table(TABLE_ITEM_PROPERTY),
  2579. Database::get_course_table(TABLE_TOOL_LIST),
  2580. Database::get_course_table(TABLE_TOOL_INTRO),
  2581. Database::get_course_table(TABLE_COURSE_SETTING),
  2582. Database::get_course_table(TABLE_SURVEY),
  2583. Database::get_course_table(TABLE_SURVEY_QUESTION),
  2584. Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION),
  2585. Database::get_course_table(TABLE_SURVEY_INVITATION),
  2586. Database::get_course_table(TABLE_SURVEY_ANSWER),
  2587. Database::get_course_table(TABLE_SURVEY_QUESTION_GROUP),
  2588. Database::get_course_table(TABLE_SURVEY_REPORT),
  2589. Database::get_course_table(TABLE_GLOSSARY),
  2590. Database::get_course_table(TABLE_LINK),
  2591. Database::get_course_table(TABLE_LINK_CATEGORY),
  2592. Database::get_course_table(TABLE_GROUP),
  2593. Database::get_course_table(TABLE_GROUP_USER),
  2594. Database::get_course_table(TABLE_GROUP_TUTOR),
  2595. Database::get_course_table(TABLE_GROUP_CATEGORY),
  2596. Database::get_course_table(TABLE_DROPBOX_CATEGORY),
  2597. Database::get_course_table(TABLE_DROPBOX_FEEDBACK),
  2598. Database::get_course_table(TABLE_DROPBOX_POST),
  2599. Database::get_course_table(TABLE_DROPBOX_FILE),
  2600. Database::get_course_table(TABLE_DROPBOX_PERSON),
  2601. ];
  2602. foreach ($truncateTables as $table) {
  2603. $sql = "TRUNCATE $table";
  2604. Database::query($sql);
  2605. echo $sql.PHP_EOL;
  2606. }
  2607. $table = Database::get_course_table(TABLE_ITEM_PROPERTY);
  2608. $sql = "DELETE FROM $table WHERE tool = 'calendar_event'";
  2609. Database::query($sql);
  2610. echo $sql.PHP_EOL;
  2611. }
  2612. /**
  2613. * If csv file ends with '"' character then a '";' is added.
  2614. *
  2615. * @param string $file
  2616. */
  2617. private function fixCSVFile($file)
  2618. {
  2619. /*$f = fopen($file, 'r+');
  2620. $cursor = -1;
  2621. fseek($f, $cursor, SEEK_END);
  2622. $char = fgetc($f);
  2623. while ($char === "\n" || $char === "\r") {
  2624. fseek($f, $cursor--, SEEK_END);
  2625. $char = fgetc($f);
  2626. }
  2627. if ($char === "\"") {
  2628. fseek($f, -1, SEEK_CUR);
  2629. fwrite($f, '";');
  2630. }*/
  2631. }
  2632. }
  2633. $logger = new Logger('cron');
  2634. $emails = isset($_configuration['cron_notification_mails']) ? $_configuration['cron_notification_mails'] : null;
  2635. $minLevel = Logger::DEBUG;
  2636. if (!is_array($emails)) {
  2637. $emails = [$emails];
  2638. }
  2639. $subject = "Cron main/cron/import_csv.php ".date('Y-m-d h:i:s');
  2640. $from = api_get_setting('emailAdministrator');
  2641. /*
  2642. if (!empty($emails)) {
  2643. foreach ($emails as $email) {
  2644. $stream = new NativeMailerHandler($email, $subject, $from, $minLevel);
  2645. $logger->pushHandler(new BufferHandler($stream, 0, $minLevel));
  2646. }
  2647. }*/
  2648. $stream = new StreamHandler(
  2649. api_get_path(SYS_ARCHIVE_PATH).'import_csv.log',
  2650. $minLevel
  2651. );
  2652. $logger->pushHandler(new BufferHandler($stream, 0, $minLevel));
  2653. $logger->pushHandler(new RotatingFileHandler('import_csv', 5, $minLevel));
  2654. $cronImportCSVConditions = isset($_configuration['cron_import_csv_conditions']) ? $_configuration['cron_import_csv_conditions'] : null;
  2655. echo 'See the error log here: '.api_get_path(SYS_ARCHIVE_PATH).'import_csv.log'."\n";
  2656. $import = new ImportCsv($logger, $cronImportCSVConditions);
  2657. if (isset($_configuration['default_admin_user_id_for_cron'])) {
  2658. $import->defaultAdminId = $_configuration['default_admin_user_id_for_cron'];
  2659. }
  2660. // @todo in production disable the dump option
  2661. $dump = false;
  2662. if (isset($argv[1]) && $argv[1] = '--dump') {
  2663. $dump = true;
  2664. }
  2665. if (isset($_configuration['import_csv_disable_dump']) &&
  2666. $_configuration['import_csv_disable_dump'] == true
  2667. ) {
  2668. $import->setDumpValues(false);
  2669. } else {
  2670. $import->setDumpValues($dump);
  2671. }
  2672. $import->setUpdateEmailToDummy(api_get_configuration_value('update_users_email_to_dummy_except_admins'));
  2673. // Do not moves the files to treated
  2674. if (isset($_configuration['import_csv_test'])) {
  2675. $import->test = $_configuration['import_csv_test'];
  2676. } else {
  2677. $import->test = true;
  2678. }
  2679. $timeStart = microtime(true);
  2680. $import->run();
  2681. $timeEnd = microtime(true);
  2682. $executionTime = round(($timeEnd - $timeStart) / 60, 2);
  2683. $logger->addInfo("Total execution Time $executionTime Min");
  2684. if (isset($_configuration['import_csv_fix_permissions']) &&
  2685. $_configuration['import_csv_fix_permissions'] == true
  2686. ) {
  2687. $command = "sudo find ".api_get_path(SYS_COURSE_PATH)." -type d -exec chmod 777 {} \; ";
  2688. echo "Executing: ".$command.PHP_EOL;
  2689. system($command);
  2690. $command = "sudo find ".api_get_path(SYS_CODE_PATH)."upload/users -type d -exec chmod 777 {} \;";
  2691. echo "Executing: ".$command.PHP_EOL;
  2692. system($command);
  2693. }