import_csv.php 99 KB

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