tracking.lib.php 286 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823
  1. <?php
  2. /* For licensing terms, see /license.txt */
  3. require_once api_get_path(SYS_CODE_PATH).'exercice/exercise.lib.php';
  4. require_once api_get_path(SYS_CODE_PATH).'newscorm/learnpathList.class.php';
  5. use CpChart\Classes\pData as pData;
  6. use CpChart\Classes\pImage as pImage;
  7. use CpChart\Classes\pCache as pCache;
  8. /**
  9. * Class Tracking
  10. *
  11. * @author Julio Montoya <gugli100@gmail.com>
  12. * @package chamilo.library
  13. */
  14. class Tracking
  15. {
  16. /**
  17. * @param int $user_id
  18. * @param array $courseInfo
  19. * @param int $session_id
  20. * @param string $origin
  21. * @param bool $export_csv
  22. * @param int $lp_id
  23. * @param int $lp_item_id
  24. * @param int $extendId
  25. * @param int $extendAttemptId
  26. * @param string $extendedAttempt
  27. * @param string $extendedAll
  28. * @param string $type classic or simple
  29. * @return null|string
  30. */
  31. public static function getLpStats(
  32. $user_id,
  33. $courseInfo,
  34. $session_id,
  35. $origin,
  36. $export_csv,
  37. $lp_id,
  38. $lp_item_id = null,
  39. $extendId = null,
  40. $extendAttemptId = null,
  41. $extendedAttempt = null,
  42. $extendedAll = null,
  43. $type = 'classic'
  44. ) {
  45. if (empty($courseInfo) || empty($lp_id)) {
  46. return null;
  47. }
  48. $lp_id = intval($lp_id);
  49. $lp_item_id = intval($lp_item_id);
  50. $user_id = intval($user_id);
  51. $session_id = intval($session_id);
  52. $origin = Security::remove_XSS($origin);
  53. $list = learnpath :: get_flat_ordered_items_list($lp_id, 0, $courseInfo['real_id']);
  54. $is_allowed_to_edit = api_is_allowed_to_edit(null, true);
  55. $course_id = $courseInfo['real_id'];
  56. $courseCode = $courseInfo['code'];
  57. $session_condition = api_get_session_condition($session_id);
  58. // Extend all button
  59. $output = null;
  60. $extend_all = 0;
  61. if ($origin == 'tracking') {
  62. $url_suffix = '&session_id=' . $session_id . '&course=' . $courseCode . '&student_id=' . $user_id . '&lp_id=' . $lp_id . '&origin=' . $origin;
  63. } else {
  64. $url_suffix = '&lp_id=' . $lp_id;
  65. }
  66. if (!empty($extendedAll)) {
  67. $extend_all_link = Display::url(
  68. Display::return_icon('view_less_stats.gif', get_lang('HideAllAttempts')),
  69. api_get_self() . '?action=stats' . $url_suffix
  70. );
  71. $extend_all = 1;
  72. } else {
  73. $extend_all_link = Display::url(
  74. Display::return_icon('view_more_stats.gif', get_lang('ShowAllAttempts')),
  75. api_get_self() . '?action=stats&extend_all=1' . $url_suffix
  76. );
  77. }
  78. if ($origin != 'tracking') {
  79. $output .= Display::page_header(get_lang('ScormMystatus'));
  80. }
  81. $actionColumn = null;
  82. if ($type == 'classic') {
  83. $actionColumn = ' <th>' . get_lang('Actions') . '</th>';
  84. }
  85. $output .= '<table class="data_table">
  86. <tr>
  87. <th width="16">' . $extend_all_link . '</th>
  88. <th colspan="4">
  89. ' . get_lang('ScormLessonTitle') .'
  90. </th>
  91. <th colspan="2">
  92. ' . get_lang('ScormStatus') . '
  93. </th>
  94. <th colspan="2">
  95. ' . get_lang('ScormScore') . '
  96. </th>
  97. <th colspan="2">
  98. ' . get_lang('ScormTime') . '
  99. </th>
  100. '.$actionColumn.'
  101. </tr>';
  102. // Going through the items using the $items[] array instead of the database order ensures
  103. // we get them in the same order as in the imsmanifest file, which is rather random when using
  104. // the database table.
  105. $TBL_LP_ITEM = Database :: get_course_table(TABLE_LP_ITEM);
  106. $TBL_LP_ITEM_VIEW = Database :: get_course_table(TABLE_LP_ITEM_VIEW);
  107. $TBL_LP_VIEW = Database :: get_course_table(TABLE_LP_VIEW);
  108. $tbl_quiz_questions = Database :: get_course_table(TABLE_QUIZ_QUESTION);
  109. $TBL_QUIZ = Database :: get_course_table(TABLE_QUIZ_TEST);
  110. $tbl_stats_exercices = Database :: get_statistic_table(TABLE_STATISTIC_TRACK_E_EXERCICES);
  111. $tbl_stats_attempts = Database :: get_statistic_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
  112. $sql = "SELECT max(view_count)
  113. FROM $TBL_LP_VIEW
  114. WHERE
  115. c_id = $course_id AND
  116. lp_id = $lp_id AND
  117. user_id = $user_id
  118. $session_condition";
  119. $res = Database::query($sql);
  120. $view = '';
  121. if (Database :: num_rows($res) > 0) {
  122. $myrow = Database :: fetch_array($res);
  123. $view = $myrow[0];
  124. }
  125. $counter = 0;
  126. $total_time = 0;
  127. $h = get_lang('h');
  128. if (!empty($export_csv)) {
  129. $csv_content[] = array(
  130. get_lang('ScormLessonTitle'),
  131. get_lang('ScormStatus'),
  132. get_lang('ScormScore'),
  133. get_lang('ScormTime')
  134. );
  135. }
  136. $result_disabled_ext_all = true;
  137. $chapterTypes = learnpath::getChapterTypes();
  138. // Show lp items
  139. if (is_array($list) && count($list) > 0) {
  140. foreach ($list as $my_item_id) {
  141. $extend_this = 0;
  142. $order = 'DESC';
  143. if ((!empty($extendId) && $extendId == $my_item_id) || $extend_all) {
  144. $extend_this = 1;
  145. $order = 'ASC';
  146. }
  147. // Prepare statement to go through each attempt.
  148. $viewCondition = null;
  149. if (!empty($view)) {
  150. $viewCondition = " AND v.view_count = $view ";
  151. }
  152. $sql = "SELECT
  153. iv.status as mystatus,
  154. v.view_count as mycount,
  155. iv.score as myscore,
  156. iv.total_time as mytime,
  157. i.id as myid,
  158. i.lp_id as mylpid,
  159. iv.lp_view_id as mylpviewid,
  160. i.title as mytitle,
  161. i.max_score as mymaxscore,
  162. iv.max_score as myviewmaxscore,
  163. i.item_type as item_type,
  164. iv.view_count as iv_view_count,
  165. iv.id as iv_id,
  166. path
  167. FROM $TBL_LP_ITEM as i
  168. INNER JOIN $TBL_LP_ITEM_VIEW as iv
  169. ON (i.id = iv.lp_item_id AND i.c_id = $course_id AND iv.c_id = $course_id)
  170. INNER JOIN $TBL_LP_VIEW as v
  171. ON (iv.lp_view_id = v.id AND v.c_id = $course_id)
  172. WHERE
  173. i.id = $my_item_id AND
  174. i.lp_id = $lp_id AND
  175. v.user_id = $user_id AND
  176. v.session_id = $session_id
  177. $viewCondition
  178. ORDER BY iv.view_count $order ";
  179. $result = Database::query($sql);
  180. $num = Database :: num_rows($result);
  181. $time_for_total = 'NaN';
  182. // Extend all
  183. if (($extend_this || $extend_all) && $num > 0) {
  184. $row = Database :: fetch_array($result);
  185. $result_disabled_ext_all = false;
  186. if ($row['item_type'] == 'quiz') {
  187. // Check results_disabled in quiz table.
  188. $my_path = Database::escape_string($row['path']);
  189. $sql = "SELECT results_disabled
  190. FROM $TBL_QUIZ
  191. WHERE
  192. c_id = $course_id AND
  193. id ='" . $my_path . "'";
  194. $res_result_disabled = Database::query($sql);
  195. $row_result_disabled = Database::fetch_row($res_result_disabled);
  196. if (Database::num_rows($res_result_disabled) > 0 &&
  197. (int) $row_result_disabled[0] === 1
  198. ) {
  199. $result_disabled_ext_all = true;
  200. }
  201. }
  202. // If there are several attempts, and the link to extend has been clicked, show each attempt...
  203. if (($counter % 2) == 0) {
  204. $oddclass = 'row_odd';
  205. } else {
  206. $oddclass = 'row_even';
  207. }
  208. $extend_link = '';
  209. if (!empty($inter_num)) {
  210. $extend_link = Display::url(
  211. Display::return_icon('visible.gif', get_lang('HideAttemptView')),
  212. api_get_self() . '?action=stats&fold_id=' . $my_item_id . $url_suffix
  213. );
  214. }
  215. $title = $row['mytitle'];
  216. if (empty($title)) {
  217. $title = rl_get_resource_name($courseInfo['code'], $lp_id, $row['myid']);
  218. }
  219. if (in_array($row['item_type'], $chapterTypes)) {
  220. $title = "<h4> $title </h4>";
  221. }
  222. $lesson_status = $row['mystatus'];
  223. $title = Security::remove_XSS($title);
  224. $counter++;
  225. $action = null;
  226. if ($type == 'classic') {
  227. $action = '<td></td>';
  228. }
  229. if (in_array($row['item_type'], $chapterTypes)) {
  230. $output .= '<tr class="'.$oddclass.'">
  231. <td>'.$extend_link.'</td>
  232. <td colspan="4">
  233. '.$title.'
  234. </td>
  235. <td colspan="2">'.learnpathItem::humanize_status($lesson_status, true, $type).'</td>
  236. <td colspan="2"></td>
  237. <td colspan="2"></td>
  238. '.$action.'
  239. </tr>';
  240. continue;
  241. } else {
  242. $output .= '<tr class="'.$oddclass.'">
  243. <td>'.$extend_link.'</td>
  244. <td colspan="4">
  245. '.$title.'
  246. </td>
  247. <td colspan="2"></td>
  248. <td colspan="2"></td>
  249. <td colspan="2"></td>
  250. '.$action.'
  251. </tr>';
  252. }
  253. $attemptCount = 1;
  254. do {
  255. // Check if there are interactions below.
  256. $extend_attempt_link = '';
  257. $extend_this_attempt = 0;
  258. if ((learnpath::get_interactions_count_from_db($row['iv_id'], $course_id) > 0 ||
  259. learnpath::get_objectives_count_from_db($row['iv_id'], $course_id) > 0) &&
  260. !$extend_all
  261. ) {
  262. if ($extendAttemptId == $row['iv_id']) {
  263. // The extend button for this attempt has been clicked.
  264. $extend_this_attempt = 1;
  265. $extend_attempt_link = Display::url(
  266. Display::return_icon('visible.gif', get_lang('HideAttemptView')),
  267. api_get_self() . '?action=stats&extend_id=' . $my_item_id . '&fold_attempt_id=' . $row['iv_id'] . $url_suffix
  268. );
  269. } else { // Same case if fold_attempt_id is set, so not implemented explicitly.
  270. // The extend button for this attempt has not been clicked.
  271. $extend_attempt_link = Display::url(
  272. Display::return_icon('invisible.gif', get_lang('ExtendAttemptView')),
  273. api_get_self() . '?action=stats&extend_id=' . $my_item_id . '&extend_attempt_id=' . $row['iv_id'] . $url_suffix
  274. );
  275. }
  276. }
  277. if (($counter % 2) == 0) {
  278. $oddclass = 'row_odd';
  279. } else {
  280. $oddclass = 'row_even';
  281. }
  282. $lesson_status = $row['mystatus'];
  283. $score = $row['myscore'];
  284. $time_for_total = $row['mytime'];
  285. $time = learnpathItem :: getScormTimeFromParameter('js', $row['mytime']);
  286. if ($score == 0) {
  287. $maxscore = $row['mymaxscore'];
  288. } else {
  289. if ($row['item_type'] == 'sco') {
  290. if (!empty($row['myviewmaxscore']) && $row['myviewmaxscore'] > 0) {
  291. $maxscore = $row['myviewmaxscore'];
  292. } elseif ($row['myviewmaxscore'] === '') {
  293. $maxscore = 0;
  294. } else {
  295. $maxscore = $row['mymaxscore'];
  296. }
  297. } else {
  298. $maxscore = $row['mymaxscore'];
  299. }
  300. }
  301. // Remove "NaN" if any (@todo: locate the source of these NaN)
  302. $time = str_replace('NaN', '00' . $h . '00\'00"', $time);
  303. if ($row['item_type'] != 'dokeos_chapter') {
  304. if (!$is_allowed_to_edit && $result_disabled_ext_all) {
  305. $view_score = Display::return_icon('invisible.gif', get_lang('ResultsHiddenByExerciseSetting'));
  306. } else {
  307. switch ($row['item_type']) {
  308. case 'sco':
  309. if ($maxscore == 0) {
  310. $view_score = $score;
  311. } else {
  312. $view_score = show_score($score, $maxscore, false);
  313. }
  314. break;
  315. case 'document':
  316. $view_score = ($score == 0 ? '/' : show_score($score, $maxscore, false));
  317. break;
  318. default:
  319. $view_score = show_score($score, $maxscore, false);
  320. break;
  321. }
  322. }
  323. $action = null;
  324. if ($type == 'classic') {
  325. $action = '<td></td>';
  326. }
  327. $output .= '<tr class="' . $oddclass . '">
  328. <td></td>
  329. <td>' . $extend_attempt_link . '</td>
  330. <td colspan="3">' . get_lang('Attempt') . ' ' . $attemptCount . '</td>
  331. <td colspan="2">' . learnpathItem::humanize_status($lesson_status, true, $type) . '</td>
  332. <td colspan="2">' . $view_score . '</td>
  333. <td colspan="2">' . $time . '</td>
  334. '.$action.'
  335. </tr>';
  336. $attemptCount++;
  337. if (!empty($export_csv)) {
  338. $temp = array();
  339. $temp[] = $title = Security::remove_XSS($title);
  340. $temp[] = Security::remove_XSS(learnpathItem::humanize_status($lesson_status, false, $type));
  341. if ($row['item_type'] == 'quiz') {
  342. if (!$is_allowed_to_edit && $result_disabled_ext_all) {
  343. $temp[] = '/';
  344. } else {
  345. $temp[] = ($score == 0 ? '0/' . $maxscore : ($maxscore == 0 ? $score : $score . '/' . float_format($maxscore, 1)));
  346. }
  347. } else {
  348. $temp[] = ($score == 0 ? '/' : ($maxscore == 0 ? $score : $score . '/' . float_format($maxscore, 1)));
  349. }
  350. $temp[] = $time;
  351. $csv_content[] = $temp;
  352. }
  353. }
  354. $counter++;
  355. $action = null;
  356. if ($type == 'classic') {
  357. $action = '<td></td>';
  358. }
  359. if ($extend_this_attempt OR $extend_all) {
  360. $list1 = learnpath :: get_iv_interactions_array($row['iv_id']);
  361. foreach ($list1 as $id => $interaction) {
  362. if (($counter % 2) == 0) {
  363. $oddclass = 'row_odd';
  364. } else {
  365. $oddclass = 'row_even';
  366. }
  367. $student_response = urldecode($interaction['student_response']);
  368. $content_student_response = explode('__|', $student_response);
  369. if (count($content_student_response) > 0) {
  370. if (count($content_student_response) >= 3) {
  371. // Pop the element off the end of array.
  372. array_pop($content_student_response);
  373. }
  374. $student_response = implode(',', $content_student_response);
  375. }
  376. $output .= '<tr class="'.$oddclass.'">
  377. <td></td>
  378. <td></td>
  379. <td></td>
  380. <td>'.$interaction['order_id'] . '</td>
  381. <td>'.$interaction['id'] . '</td>
  382. <td colspan="2">' . $interaction['type'].'</td>
  383. <td>'.$student_response . '</td>
  384. <td>'.$interaction['result'] . '</td>
  385. <td>'.$interaction['latency'] . '</td>
  386. <td>'.$interaction['time'] . '</td>
  387. '.$action.'
  388. </tr>';
  389. $counter++;
  390. }
  391. $list2 = learnpath :: get_iv_objectives_array($row['iv_id']);
  392. foreach ($list2 as $id => $interaction) {
  393. if (($counter % 2) == 0) {
  394. $oddclass = 'row_odd';
  395. } else {
  396. $oddclass = 'row_even';
  397. }
  398. $output .= '<tr class="'.$oddclass.'">
  399. <td></td>
  400. <td></td>
  401. <td></td>
  402. <td>' . $interaction['order_id'] . '</td>
  403. <td colspan="2">' . $interaction['objective_id'] . '</td>
  404. <td colspan="2">' . $interaction['status'] .'</td>
  405. <td>' . $interaction['score_raw'] . '</td>
  406. <td>' . $interaction['score_max'] . '</td>
  407. <td>' . $interaction['score_min'] . '</td>
  408. '.$action.'
  409. </tr>';
  410. $counter++;
  411. }
  412. }
  413. } while ($row = Database :: fetch_array($result));
  414. } elseif ($num > 0) {
  415. // Not extended.
  416. $row = Database :: fetch_array($result, 'ASSOC');
  417. $my_id = $row['myid'];
  418. $my_lp_id = $row['mylpid'];
  419. $my_lp_view_id = $row['mylpviewid'];
  420. $my_path = $row['path'];
  421. $result_disabled_ext_all = false;
  422. if ($row['item_type'] == 'quiz') {
  423. // Check results_disabled in quiz table.
  424. $my_path = Database::escape_string($my_path);
  425. $sql = "SELECT results_disabled
  426. FROM $TBL_QUIZ
  427. WHERE c_id = $course_id AND id ='" . $my_path . "'";
  428. $res_result_disabled = Database::query($sql);
  429. $row_result_disabled = Database::fetch_row($res_result_disabled);
  430. if (Database::num_rows($res_result_disabled) > 0 &&
  431. (int) $row_result_disabled[0] === 1
  432. ) {
  433. $result_disabled_ext_all = true;
  434. }
  435. }
  436. // Check if there are interactions below
  437. $extend_this_attempt = 0;
  438. $inter_num = learnpath::get_interactions_count_from_db($row['iv_id'], $course_id);
  439. $objec_num = learnpath::get_objectives_count_from_db($row['iv_id'], $course_id);
  440. $extend_attempt_link = '';
  441. if ($inter_num > 0 || $objec_num > 0) {
  442. if (!empty($extendAttemptId) && $extendAttemptId == $row['iv_id']) {
  443. // The extend button for this attempt has been clicked.
  444. $extend_this_attempt = 1;
  445. $extend_attempt_link = Display::url(
  446. Display::return_icon('visible.gif', get_lang('HideAttemptView')),
  447. api_get_self() . '?action=stats&extend_id=' . $my_item_id . '&fold_attempt_id=' . $row['iv_id'] . $url_suffix
  448. );
  449. } else {
  450. // Same case if fold_attempt_id is set, so not implemented explicitly.
  451. // The extend button for this attempt has not been clicked.
  452. $extend_attempt_link = Display::url(
  453. Display::return_icon('invisible.gif', get_lang('ExtendAttemptView')),
  454. api_get_self() . '?action=stats&extend_id=' . $my_item_id . '&extend_attempt_id=' . $row['iv_id'] . $url_suffix
  455. );
  456. }
  457. }
  458. if (($counter % 2) == 0) {
  459. $oddclass = 'row_odd';
  460. } else {
  461. $oddclass = 'row_even';
  462. }
  463. $extend_link = '';
  464. if ($inter_num > 1) {
  465. $extend_link = Display::url(
  466. Display::return_icon('invisible.gif', get_lang('ExtendAttemptView')),
  467. api_get_self() . '?action=stats&extend_id=' . $my_item_id . '&extend_attempt_id=' . $row['iv_id'] . $url_suffix
  468. );
  469. }
  470. $lesson_status = $row['mystatus'];
  471. $score = $row['myscore'];
  472. $subtotal_time = $row['mytime'];
  473. while ($tmp_row = Database :: fetch_array($result)) {
  474. $subtotal_time += $tmp_row['mytime'];
  475. }
  476. $title = $row['mytitle'];
  477. // Selecting the exe_id from stats attempts tables in order to look the max score value.
  478. $sql = 'SELECT * FROM ' . $tbl_stats_exercices . '
  479. WHERE
  480. exe_exo_id="' . $row['path'] . '" AND
  481. exe_user_id="' . $user_id . '" AND
  482. orig_lp_id = "' . $lp_id . '" AND
  483. orig_lp_item_id = "' . $row['myid'] . '" AND
  484. exe_cours_id="' . $courseCode . '" AND
  485. status <> "incomplete" AND
  486. session_id = ' . $session_id . '
  487. ORDER BY exe_date DESC
  488. LIMIT 1';
  489. $resultLastAttempt = Database::query($sql);
  490. $num = Database :: num_rows($resultLastAttempt);
  491. $id_last_attempt = null;
  492. if ($num > 0) {
  493. while ($rowLA = Database :: fetch_array($resultLastAttempt)) {
  494. $id_last_attempt = $rowLA['exe_id'];
  495. }
  496. }
  497. if ($score == 0) {
  498. $maxscore = $row['mymaxscore'];
  499. } else {
  500. if ($row['item_type'] == 'sco') {
  501. if (!empty($row['myviewmaxscore']) and $row['myviewmaxscore'] > 0) {
  502. $maxscore = $row['myviewmaxscore'];
  503. } elseif ($row['myviewmaxscore'] === '') {
  504. $maxscore = 0;
  505. } else {
  506. $maxscore = $row['mymaxscore'];
  507. }
  508. } else {
  509. if ($row['item_type'] == 'quiz') {
  510. // Get score and total time from last attempt of a exercise en lp.
  511. $sql = "SELECT score
  512. FROM $TBL_LP_ITEM_VIEW
  513. WHERE
  514. c_id = $course_id AND
  515. lp_item_id = '" . (int) $my_id . "' AND
  516. lp_view_id = '" . (int) $my_lp_view_id . "'
  517. ORDER BY view_count DESC limit 1";
  518. $res_score = Database::query($sql);
  519. $row_score = Database::fetch_array($res_score);
  520. $sql = "SELECT SUM(total_time) as total_time
  521. FROM $TBL_LP_ITEM_VIEW
  522. WHERE
  523. c_id = $course_id AND
  524. lp_item_id = '" . (int) $my_id . "' AND
  525. lp_view_id = '" . (int) $my_lp_view_id . "'";
  526. $res_time = Database::query($sql);
  527. $row_time = Database::fetch_array($res_time);
  528. if (Database::num_rows($res_score) > 0 &&
  529. Database::num_rows($res_time) > 0
  530. ) {
  531. $score = (float) $row_score['score'];
  532. $subtotal_time = (int) $row_time['total_time'];
  533. } else {
  534. $score = 0;
  535. $subtotal_time = 0;
  536. }
  537. // Selecting the max score from an attempt.
  538. $sql = "SELECT SUM(t.ponderation) as maxscore
  539. FROM (
  540. SELECT DISTINCT
  541. question_id, marks, ponderation
  542. FROM $tbl_stats_attempts as at
  543. INNER JOIN $tbl_quiz_questions as q
  544. ON (q.id = at.question_id AND q.c_id = $course_id)
  545. WHERE exe_id ='$id_last_attempt'
  546. ) as t";
  547. $result = Database::query($sql);
  548. $row_max_score = Database :: fetch_array($result);
  549. $maxscore = $row_max_score['maxscore'];
  550. } else {
  551. $maxscore = $row['mymaxscore'];
  552. }
  553. }
  554. }
  555. $time_for_total = $subtotal_time;
  556. $time = learnpathItem::getScormTimeFromParameter('js', $subtotal_time);
  557. if (empty($title)) {
  558. $title = rl_get_resource_name($courseInfo['code'], $lp_id, $row['myid']);
  559. }
  560. $action = null;
  561. if ($type == 'classic') {
  562. $action = '<td></td>';
  563. }
  564. if (in_array($row['item_type'], $chapterTypes)) {
  565. $title = Security::remove_XSS($title);
  566. $output .= '<tr class="'.$oddclass.'">
  567. <td>'.$extend_link.'</td>
  568. <td colspan="4">
  569. <h4>'.$title.'</h4>
  570. </td>
  571. <td colspan="2">'.learnpathitem::humanize_status($lesson_status).'</td>
  572. <td colspan="2"></td>
  573. <td colspan="2"></td>
  574. '.$action.'
  575. </tr>';
  576. } else {
  577. $correct_test_link = '-';
  578. if ($row['item_type'] == 'quiz') {
  579. $my_url_suffix = '&course=' . $courseCode . '&student_id=' . $user_id . '&lp_id=' . intval($row['mylpid']) . '&origin=' . $origin;
  580. $sql = 'SELECT * FROM ' . $tbl_stats_exercices . '
  581. WHERE
  582. exe_exo_id="' . $row['path'] . '" AND
  583. exe_user_id="' . $user_id . '" AND
  584. orig_lp_id = "' . $lp_id . '" AND
  585. orig_lp_item_id = "' . $row['myid'] . '" AND
  586. exe_cours_id="' . $courseCode. '" AND
  587. status <> "incomplete" AND
  588. session_id = ' . $session_id . '
  589. ORDER BY exe_date DESC ';
  590. $resultLastAttempt = Database::query($sql);
  591. $num = Database :: num_rows($resultLastAttempt);
  592. if ($num > 0) {
  593. if ($extendedAttempt == 1 &&
  594. $lp_id == $my_lp_id &&
  595. $lp_item_id == $my_id
  596. ) {
  597. $correct_test_link = Display::url(
  598. Display::return_icon('view_less_stats.gif', get_lang('HideAllAttempts')),
  599. api_get_self() . '?action=stats' . $my_url_suffix . '&session_id=' . $session_id . '&lp_item_id=' . $my_id
  600. );
  601. } else {
  602. $correct_test_link = Display::url(
  603. Display::return_icon('view_more_stats.gif', get_lang('ShowAllAttemptsByExercise')),
  604. api_get_self() . '?action=stats&extend_attempt=1' . $my_url_suffix . '&session_id=' . $session_id . '&lp_item_id=' . $my_id
  605. );
  606. }
  607. }
  608. }
  609. $title = Security::remove_XSS($title);
  610. $action = null;
  611. if ($type == 'classic') {
  612. $action = '<td>' . $correct_test_link . '</td>';
  613. }
  614. if ($lp_id == $my_lp_id && false) {
  615. $output .= '<tr class =' . $oddclass . '>
  616. <td>' . $extend_link . '</td>
  617. <td colspan="4">' . $title . '</td>
  618. <td colspan="2">&nbsp;</td>
  619. <td colspan="2">&nbsp;</td>
  620. <td colspan="2">&nbsp;</td>
  621. '.$action.'
  622. </tr>';
  623. $output .= '</tr>';
  624. } else {
  625. if ($lp_id == $my_lp_id && $lp_item_id == $my_id) {
  626. $output .= "<tr class='$oddclass'>";
  627. } else {
  628. $output .= "<tr class='$oddclass'>";
  629. }
  630. /*if (($is_allowed_to_edit || api_is_drh()) && isset($_GET['lp_id']) && isset($course_code)) {
  631. $lp = new learnpath($course_code, $_GET['lp_id'], api_get_user_id());
  632. $lp->set_course_int_id($course_id);
  633. $item_path_url = $lp->get_link('http', $my_id, false);
  634. $item_path_url .= "&width=600";
  635. $title = Display::url($title, $item_path_url, array('class' => 'ajax'));
  636. }*/
  637. $scoreItem = null;
  638. if ($row['item_type'] == 'quiz') {
  639. if (!$is_allowed_to_edit && $result_disabled_ext_all) {
  640. $scoreItem .= Display::return_icon(
  641. 'invisible.gif',
  642. get_lang('ResultsHiddenByExerciseSetting')
  643. );
  644. } else {
  645. $scoreItem .= show_score($score, $maxscore, false);
  646. }
  647. } else {
  648. $scoreItem .= $score == 0 ? '/' : ($maxscore == 0 ? $score : $score . '/' . $maxscore);
  649. }
  650. $output .= '
  651. <td>'.$extend_link.'</td>
  652. <td colspan="4">' . $title . '</td>
  653. <td colspan="2">' . learnpathitem::humanize_status($lesson_status) .'</td>
  654. <td colspan="2">'.$scoreItem.'</td>
  655. <td colspan="2">'.$time.'</td>
  656. '.$action.'
  657. ';
  658. $output .= '</tr>';
  659. }
  660. if (!empty($export_csv)) {
  661. $temp = array();
  662. $temp[] = api_html_entity_decode($title, ENT_QUOTES);
  663. $temp[] = api_html_entity_decode($lesson_status, ENT_QUOTES);
  664. if ($row['item_type'] == 'quiz') {
  665. if (!$is_allowed_to_edit && $result_disabled_ext_all) {
  666. $temp[] = '/';
  667. } else {
  668. $temp[] = ($score == 0 ? '0/' . $maxscore : ($maxscore == 0 ? $score : $score . '/' . float_format($maxscore, 1)));
  669. }
  670. } else {
  671. $temp[] = ($score == 0 ? '/' : ($maxscore == 0 ? $score : $score . '/' . float_format($maxscore, 1)));
  672. }
  673. $temp[] = $time;
  674. $csv_content[] = $temp;
  675. }
  676. }
  677. $counter++;
  678. $action = null;
  679. if ($type == 'classic') {
  680. $action = '<td></td>';
  681. }
  682. if ($extend_this_attempt OR $extend_all) {
  683. $list1 = learnpath :: get_iv_interactions_array($row['iv_id']);
  684. foreach ($list1 as $id => $interaction) {
  685. if (($counter % 2) == 0) {
  686. $oddclass = 'row_odd';
  687. } else {
  688. $oddclass = 'row_even';
  689. }
  690. $output .= '<tr class="'.$oddclass.'">
  691. <td></td>
  692. <td></td>
  693. <td></td>
  694. <td>'.$interaction['order_id'].'</td>
  695. <td>'.$interaction['id'].'</td>
  696. <td colspan="2">' . $interaction['type'].'</td>
  697. <td>'.urldecode($interaction['student_response']).'</td>
  698. <td>'.$interaction['result'].'</td>
  699. <td>'.$interaction['latency'].'</td>
  700. <td>'.$interaction['time'].'</td>
  701. '.$action.'
  702. </tr>';
  703. $counter++;
  704. }
  705. $list2 = learnpath :: get_iv_objectives_array($row['iv_id']);
  706. foreach ($list2 as $id => $interaction) {
  707. if (($counter % 2) == 0) {
  708. $oddclass = 'row_odd';
  709. } else {
  710. $oddclass = 'row_even';
  711. }
  712. $output .= '<tr class="'.$oddclass.'">
  713. <td></td>
  714. <td></td>
  715. <td></td>
  716. <td>' . $interaction['order_id'] . '</td>
  717. <td colspan="2">'.$interaction['objective_id'] . '</td>
  718. <td colspan="2">' . $interaction['status'] . '</td>
  719. <td>' . $interaction['score_raw'].'</td>
  720. <td>' . $interaction['score_max'] .'</td>
  721. <td>' . $interaction['score_min'].'</td>
  722. '.$action.'
  723. </tr>';
  724. $counter++;
  725. }
  726. }
  727. // Attempts listing by exercise.
  728. if ($lp_id == $my_lp_id && $lp_item_id== $my_id && $extendedAttempt) {
  729. // Get attempts of a exercise.
  730. if (!empty($lp_id) &&
  731. !empty($lp_item_id) &&
  732. $row['item_type'] === 'quiz'
  733. ) {
  734. $sql = "SELECT path FROM $TBL_LP_ITEM
  735. WHERE
  736. c_id = $course_id AND
  737. id = '$lp_item_id' AND
  738. lp_id = '$lp_id'";
  739. $res_path = Database::query($sql);
  740. $row_path = Database::fetch_array($res_path);
  741. if (Database::num_rows($res_path) > 0) {
  742. $sql = 'SELECT * FROM ' . $tbl_stats_exercices . '
  743. WHERE
  744. exe_exo_id="' . (int) $row_path['path'] . '" AND
  745. status <> "incomplete" AND
  746. exe_user_id="' . $user_id . '" AND
  747. orig_lp_id = "' . (int) $lp_id . '" AND
  748. orig_lp_item_id = "' . (int) $lp_item_id . '" AND
  749. exe_cours_id="' . $courseCode . '" AND
  750. session_id = ' . $session_id . '
  751. ORDER BY exe_date';
  752. $res_attempts = Database::query($sql);
  753. $num_attempts = Database::num_rows($res_attempts);
  754. if ($num_attempts > 0) {
  755. $n = 1;
  756. while ($row_attempts = Database :: fetch_array($res_attempts)) {
  757. $my_score = $row_attempts['exe_result'];
  758. $my_maxscore = $row_attempts['exe_weighting'];
  759. $my_exe_id = $row_attempts['exe_id'];
  760. $my_orig_lp = $row_attempts['orig_lp_id'];
  761. $my_orig_lp_item = $row_attempts['orig_lp_item_id'];
  762. $my_exo_exe_id = $row_attempts['exe_exo_id'];
  763. $mktime_start_date = api_strtotime($row_attempts['start_date'], 'UTC');
  764. $mktime_exe_date = api_strtotime($row_attempts['exe_date'], 'UTC');
  765. if ($mktime_start_date && $mktime_exe_date) {
  766. $mytime = ((int) $mktime_exe_date - (int) $mktime_start_date);
  767. $time_attemp = learnpathItem :: getScormTimeFromParameter('js', $mytime);
  768. $time_attemp = str_replace('NaN', '00' . $h . '00\'00"', $time_attemp);
  769. } else {
  770. $time_attemp = ' - ';
  771. }
  772. if (!$is_allowed_to_edit && $result_disabled_ext_all) {
  773. $view_score = Display::return_icon('invisible.gif', get_lang('ResultsHiddenByExerciseSetting'));
  774. } else {
  775. // Show only float when need it
  776. if ($my_score == 0) {
  777. $view_score = show_score(0, $my_maxscore, false);
  778. } else {
  779. if ($my_maxscore == 0) {
  780. $view_score = $my_score;
  781. } else {
  782. $view_score = show_score($my_score, $my_maxscore, false);
  783. }
  784. }
  785. }
  786. $my_lesson_status = $row_attempts['status'];
  787. if ($my_lesson_status == '') {
  788. $my_lesson_status = learnpathitem::humanize_status('completed');
  789. } elseif ($my_lesson_status == 'incomplete') {
  790. $my_lesson_status = learnpathitem::humanize_status('incomplete');
  791. }
  792. $output .= '<tr class="' . $oddclass . '" >
  793. <td></td>
  794. <td>' . $extend_attempt_link . '</td>
  795. <td colspan="3">' . get_lang('Attempt').' '. $n.'</td>
  796. <td colspan="2">' . $my_lesson_status . '</td>
  797. <td colspan="2">'.$view_score . '</td>
  798. <td colspan="2">'.$time_attemp . '</td>';
  799. if ($action == 'classic') {
  800. if ($origin != 'tracking') {
  801. if (!$is_allowed_to_edit && $result_disabled_ext_all) {
  802. $output .= '<td>
  803. <img src="' . api_get_path(WEB_IMG_PATH) . 'quiz_na.gif" alt="' . get_lang('ShowAttempt') . '" title="' . get_lang('ShowAttempt') . '">
  804. </td>';
  805. } else {
  806. $output .= '<td>
  807. <a href="../exercice/exercise_show.php?origin=' . $origin . '&id=' . $my_exe_id . '&cidReq=' . $courseCode . '" target="_parent">
  808. <img src="' . api_get_path(WEB_IMG_PATH) . 'quiz.gif" alt="' . get_lang('ShowAttempt') . '" title="' . get_lang('ShowAttempt') . '">
  809. </a></td>';
  810. }
  811. } else {
  812. if (!$is_allowed_to_edit && $result_disabled_ext_all) {
  813. $output .= '<td>
  814. <img src="' . api_get_path(WEB_IMG_PATH) . 'quiz_na.gif" alt="' . get_lang('ShowAndQualifyAttempt') . '" title="' . get_lang('ShowAndQualifyAttempt') . '"></td>';
  815. } else {
  816. $output .= '<td>
  817. <a href="../exercice/exercise_show.php?cidReq=' . $courseCode . '&origin=correct_exercise_in_lp&id=' . $my_exe_id . '" target="_parent">
  818. <img src="' . api_get_path(WEB_IMG_PATH) . 'quiz.gif" alt="' . get_lang('ShowAndQualifyAttempt') . '" title="' . get_lang('ShowAndQualifyAttempt') . '"></a></td>';
  819. }
  820. }
  821. }
  822. $output .= '</tr>';
  823. $n++;
  824. }
  825. }
  826. $output .= '<tr><td colspan="12">&nbsp;</td></tr>';
  827. }
  828. }
  829. }
  830. }
  831. $total_time += $time_for_total;
  832. // QUIZZ IN LP
  833. $a_my_id = array();
  834. if (!empty($my_lp_id)) {
  835. $a_my_id[] = $my_lp_id;
  836. }
  837. }
  838. }
  839. // NOT Extend all "left green cross"
  840. if (!empty($a_my_id)) {
  841. if ($extendedAttempt) {
  842. // "Right green cross" extended
  843. $total_score = self::get_avg_student_score(
  844. $user_id,
  845. $course_id,
  846. $a_my_id,
  847. $session_id,
  848. false,
  849. false
  850. );
  851. } else {
  852. // "Left green cross" extended
  853. $total_score = self::get_avg_student_score(
  854. $user_id,
  855. $course_id,
  856. $a_my_id,
  857. $session_id,
  858. false,
  859. true
  860. );
  861. }
  862. } else {
  863. // Extend all "left green cross"
  864. $total_score = self::get_avg_student_score(
  865. $user_id,
  866. $course_id,
  867. array($lp_id),
  868. $session_id,
  869. false,
  870. false
  871. );
  872. }
  873. $total_time = learnpathItem::getScormTimeFromParameter('js', $total_time);
  874. $total_time = str_replace('NaN', '00' . $h . '00\'00"', $total_time);
  875. if (!$is_allowed_to_edit && $result_disabled_ext_all) {
  876. $final_score = Display::return_icon('invisible.gif', get_lang('ResultsHiddenByExerciseSetting'));
  877. } else {
  878. if (is_numeric($total_score)) {
  879. $final_score = $total_score . '%';
  880. } else {
  881. $final_score = $total_score;
  882. }
  883. }
  884. $progress = learnpath::getProgress($lp_id, $user_id, $course_id, $session_id);
  885. if (($counter % 2) == 0) {
  886. $oddclass = 'row_odd';
  887. } else {
  888. $oddclass = 'row_even';
  889. }
  890. $action = null;
  891. if ($type == 'classic') {
  892. $action = '<td></td>';
  893. }
  894. $output .= '<tr class="'.$oddclass.'">
  895. <td></td>
  896. <td colspan="4">
  897. <i>' . get_lang('AccomplishedStepsTotal') .'</i>
  898. </td>
  899. <td colspan="2">'.$progress.'%</td>
  900. <td colspan="2">
  901. ' . $final_score.'
  902. </td>
  903. <td colspan="2">' . $total_time . '</div>
  904. '.$action.'
  905. </tr>';
  906. $output .= "</table>";
  907. if (!empty($export_csv)) {
  908. $temp = array(
  909. '',
  910. '',
  911. '',
  912. ''
  913. );
  914. $csv_content[] = $temp;
  915. $temp = array(
  916. get_lang('AccomplishedStepsTotal'),
  917. '',
  918. $final_score,
  919. $total_time
  920. );
  921. $csv_content[] = $temp;
  922. ob_end_clean();
  923. Export :: export_table_csv($csv_content, 'reporting_learning_path_details');
  924. exit;
  925. }
  926. return $output;
  927. }
  928. /**
  929. * @param int $userId
  930. *
  931. * @return array
  932. */
  933. public static function getStats($userId)
  934. {
  935. $assignedCourses = array();
  936. if (api_is_drh() && api_drh_can_access_all_session_content()) {
  937. $studentList = SessionManager::getAllUsersFromCoursesFromAllSessionFromStatus(
  938. 'drh_all',
  939. $userId,
  940. false,
  941. null,
  942. null,
  943. null,
  944. null,
  945. null,
  946. null,
  947. null,
  948. array(),
  949. array(),
  950. STUDENT
  951. );
  952. $students = array();
  953. foreach ($studentList as $studentData) {
  954. $students[] = $studentData['user_id'];
  955. }
  956. $teacherList = SessionManager::getAllUsersFromCoursesFromAllSessionFromStatus(
  957. 'drh_all',
  958. $userId,
  959. false,
  960. null,
  961. null,
  962. null,
  963. null,
  964. null,
  965. null,
  966. null,
  967. array(),
  968. array(),
  969. COURSEMANAGER
  970. );
  971. $teachers = array();
  972. foreach ($teacherList as $teacherData) {
  973. $teachers[] = $teacherData['user_id'];
  974. }
  975. $humanResources = SessionManager::getAllUsersFromCoursesFromAllSessionFromStatus(
  976. 'drh_all',
  977. $userId,
  978. false,
  979. null,
  980. null,
  981. null,
  982. null,
  983. null,
  984. null,
  985. null,
  986. array(),
  987. array(),
  988. DRH
  989. );
  990. $humanResourcesList = array();
  991. foreach ($humanResources as $item) {
  992. $humanResourcesList[] = $item['user_id'];
  993. }
  994. $platformCourses = SessionManager::getAllCoursesFollowedByUser(
  995. $userId,
  996. null,
  997. null,
  998. null,
  999. null,
  1000. null
  1001. );
  1002. $courses = array();
  1003. foreach ($platformCourses as $course) {
  1004. $courses[$course['code']] = $course['code'];
  1005. }
  1006. $sessions = SessionManager::get_sessions_followed_by_drh($userId);
  1007. } else {
  1008. $studentList = UserManager::getUsersFollowedByUser(
  1009. $userId,
  1010. STUDENT,
  1011. false,
  1012. false,
  1013. false,
  1014. null,
  1015. null,
  1016. null,
  1017. null,
  1018. null,
  1019. null,
  1020. COURSEMANAGER
  1021. );
  1022. $students = array();
  1023. foreach ($studentList as $studentData) {
  1024. $students[] = $studentData['user_id'];
  1025. }
  1026. $teacherList = UserManager::getUsersFollowedByUser(
  1027. $userId,
  1028. COURSEMANAGER,
  1029. false,
  1030. false,
  1031. false,
  1032. null,
  1033. null,
  1034. null,
  1035. null,
  1036. null,
  1037. null,
  1038. COURSEMANAGER
  1039. );
  1040. $teachers = array();
  1041. foreach ($teacherList as $teacherData) {
  1042. $teachers[] = $teacherData['user_id'];
  1043. }
  1044. $humanResources = UserManager::getUsersFollowedByUser(
  1045. $userId,
  1046. DRH,
  1047. false,
  1048. false,
  1049. false,
  1050. null,
  1051. null,
  1052. null,
  1053. null,
  1054. null,
  1055. null,
  1056. COURSEMANAGER
  1057. );
  1058. $humanResourcesList = array();
  1059. foreach ($humanResources as $item) {
  1060. $humanResourcesList[] = $item['user_id'];
  1061. }
  1062. $platformCourses = CourseManager::getCoursesFollowedByUser(
  1063. $userId,
  1064. COURSEMANAGER,
  1065. null,
  1066. null,
  1067. null,
  1068. null,
  1069. false,
  1070. null,
  1071. null,
  1072. true
  1073. );
  1074. foreach ($platformCourses as $course) {
  1075. $assignedCourses[$course['code']] = $course['code'];
  1076. }
  1077. $platformCourses = CourseManager::getCoursesFollowedByUser(
  1078. $userId,
  1079. COURSEMANAGER
  1080. );
  1081. foreach ($platformCourses as $course) {
  1082. $courses[$course['code']] = $course['code'];
  1083. }
  1084. $sessions = SessionManager::getSessionsFollowedByUser(
  1085. $userId,
  1086. COURSEMANAGER
  1087. );
  1088. }
  1089. return array(
  1090. 'drh' => $humanResourcesList,
  1091. 'teachers' => $teachers,
  1092. 'students' => $students,
  1093. 'courses' => $courses,
  1094. 'sessions' => $sessions,
  1095. 'assignedCourses' => $assignedCourses
  1096. );
  1097. }
  1098. /**
  1099. * Calculates the time spent on the platform by a user
  1100. * @param int|array User id
  1101. * @param string type of time filter: 'last_week' or 'custom'
  1102. * @param string start date date('Y-m-d H:i:s')
  1103. * @param string end date date('Y-m-d H:i:s')
  1104. * @return timestamp $nb_seconds
  1105. */
  1106. public static function get_time_spent_on_the_platform(
  1107. $userId,
  1108. $timeFilter = 'last_7_days',
  1109. $start_date = null,
  1110. $end_date = null
  1111. ) {
  1112. $tbl_track_login = Database::get_statistic_table(TABLE_STATISTIC_TRACK_E_LOGIN);
  1113. $condition_time = '';
  1114. if (is_array($userId)) {
  1115. $userList = array_map('intval', $userId);
  1116. $userCondition = " login_user_id IN ('".implode("','", $userList)."')";
  1117. } else {
  1118. $userCondition = " login_user_id = ".intval($userId);
  1119. }
  1120. if (empty($timeFilter)) {
  1121. $timeFilter = 'last_week';
  1122. }
  1123. $today = date('Y-m-d H:i:s');
  1124. switch ($timeFilter) {
  1125. case 'last_7_days':
  1126. $new_date = date('Y-m-d H:i:s', strtotime('-7 day'));
  1127. $condition_time = ' AND (login_date >= "'.$new_date.'" AND logout_date <= "'.$today.'") ';
  1128. break;
  1129. case 'last_30_days':
  1130. $new_date = date('Y-m-d H:i:s', strtotime('-30 day'));
  1131. $condition_time = ' AND (login_date >= "'.$new_date.'" AND logout_date <= "'.$today.'") ';
  1132. break;
  1133. case 'custom':
  1134. if (!empty($start_date) && !empty($end_date)) {
  1135. $start_date = Database::escape_string($start_date);
  1136. $end_date = Database::escape_string($end_date);
  1137. $condition_time = ' AND (login_date >= "'.$start_date.'" AND logout_date <= "'.$end_date.'" ) ';
  1138. }
  1139. break;
  1140. }
  1141. $sql = 'SELECT SUM(TIMESTAMPDIFF(SECOND, login_date, logout_date)) diff
  1142. FROM '.$tbl_track_login.'
  1143. WHERE '.$userCondition.$condition_time;
  1144. $rs = Database::query($sql);
  1145. $row = Database::fetch_array($rs, 'ASSOC');
  1146. $diff = $row['diff'];
  1147. if ($diff >= 0) {
  1148. return $diff;
  1149. } else {
  1150. return -1;
  1151. }
  1152. }
  1153. /**
  1154. * Calculates the time spent on the course
  1155. * @param integer $user_id
  1156. * @param string $course_code
  1157. * @param int Session id (optional)
  1158. *
  1159. * @return int Time in seconds
  1160. */
  1161. public static function get_time_spent_on_the_course($user_id, $course_code, $session_id = 0)
  1162. {
  1163. $course_code = Database::escape_string($course_code);
  1164. $session_id = intval($session_id);
  1165. $tbl_track_course = Database :: get_statistic_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
  1166. if (is_array($user_id)) {
  1167. $user_id = array_map('intval', $user_id);
  1168. $condition_user = " AND user_id IN (".implode(',',$user_id).") ";
  1169. } else {
  1170. $user_id = intval($user_id);
  1171. $condition_user = " AND user_id = '$user_id' ";
  1172. }
  1173. $sql = "SELECT SUM(UNIX_TIMESTAMP(logout_course_date) - UNIX_TIMESTAMP(login_course_date)) as nb_seconds
  1174. FROM $tbl_track_course
  1175. WHERE
  1176. UNIX_TIMESTAMP(logout_course_date) > UNIX_TIMESTAMP(login_course_date) AND
  1177. course_code='$course_code' AND
  1178. session_id = '$session_id' $condition_user";
  1179. $rs = Database::query($sql);
  1180. $row = Database::fetch_array($rs);
  1181. return $row['nb_seconds'];
  1182. }
  1183. /**
  1184. * Get first connection date for a student
  1185. * @param int $student_id
  1186. *
  1187. * @return string|bool Date format long without day or false if there are no connections
  1188. */
  1189. public static function get_first_connection_date($student_id)
  1190. {
  1191. $tbl_track_login = Database :: get_statistic_table(TABLE_STATISTIC_TRACK_E_LOGIN);
  1192. $sql = 'SELECT login_date FROM ' . $tbl_track_login . '
  1193. WHERE login_user_id = ' . intval($student_id) . '
  1194. ORDER BY login_date ASC LIMIT 0,1';
  1195. $rs = Database::query($sql);
  1196. if (Database::num_rows($rs)>0) {
  1197. if ($first_login_date = Database::result($rs, 0, 0)) {
  1198. return api_convert_and_format_date($first_login_date, DATE_FORMAT_SHORT, date_default_timezone_get());
  1199. }
  1200. }
  1201. return false;
  1202. }
  1203. /**
  1204. * Get las connection date for a student
  1205. * @param int $student_id
  1206. * @param bool $warning_message Show a warning message (optional)
  1207. * @param bool $return_timestamp True for returning results in timestamp (optional)
  1208. * @return string|int|bool Date format long without day, false if there are no connections or
  1209. * timestamp if parameter $return_timestamp is true
  1210. */
  1211. public static function get_last_connection_date($student_id, $warning_message = false, $return_timestamp = false)
  1212. {
  1213. $tbl_track_login = Database :: get_statistic_table(TABLE_STATISTIC_TRACK_E_LOGIN);
  1214. $sql = 'SELECT login_date FROM ' . $tbl_track_login . '
  1215. WHERE login_user_id = ' . intval($student_id) . '
  1216. ORDER BY login_date DESC LIMIT 0,1';
  1217. $rs = Database::query($sql);
  1218. if (Database::num_rows($rs) > 0) {
  1219. if ($last_login_date = Database::result($rs, 0, 0)) {
  1220. $last_login_date = api_get_local_time($last_login_date);
  1221. if ($return_timestamp) {
  1222. return api_strtotime($last_login_date,'UTC');
  1223. } else {
  1224. if (!$warning_message) {
  1225. return api_format_date($last_login_date, DATE_FORMAT_SHORT);
  1226. } else {
  1227. $timestamp = api_strtotime($last_login_date,'UTC');
  1228. $currentTimestamp = time();
  1229. //If the last connection is > than 7 days, the text is red
  1230. //345600 = 7 days in seconds
  1231. if ($currentTimestamp - $timestamp > 604800) {
  1232. return '<span style="color: #F00;">' . api_format_date($last_login_date, DATE_FORMAT_SHORT) . '</span>';
  1233. } else {
  1234. return api_format_date($last_login_date, DATE_FORMAT_SHORT);
  1235. }
  1236. }
  1237. }
  1238. }
  1239. }
  1240. return false;
  1241. }
  1242. /**
  1243. * Get las connection date for a student
  1244. * @param array $studentList Student id array
  1245. * @param int $days
  1246. * @param bool $getCount
  1247. * @return int
  1248. */
  1249. public static function getInactiveUsers($studentList, $days, $getCount = true)
  1250. {
  1251. if (empty($studentList)) {
  1252. return 0;
  1253. }
  1254. $days = intval($days);
  1255. $date = api_get_utc_datetime(strtotime($days.' days ago'));
  1256. $studentList = array_map('intval', $studentList);
  1257. $tbl_track_login = Database::get_statistic_table(TABLE_STATISTIC_TRACK_E_LOGIN);
  1258. $select = " SELECT login_user_id ";
  1259. if ($getCount) {
  1260. $select = " SELECT count(DISTINCT login_user_id) as count";
  1261. }
  1262. $sql = "$select
  1263. FROM $tbl_track_login
  1264. WHERE
  1265. login_user_id IN (' ". implode("','", $studentList) . "' ) AND
  1266. login_date < '$date'
  1267. ";
  1268. $rs = Database::query($sql);
  1269. if (Database::num_rows($rs) > 0) {
  1270. if ($getCount) {
  1271. $count = Database::fetch_array($rs);
  1272. return $count['count'];
  1273. }
  1274. return Database::store_result($rs, 'ASSOC');
  1275. }
  1276. return false;
  1277. }
  1278. /**
  1279. * Get first user's connection date on the course
  1280. * @param int User id
  1281. * @param string Course code
  1282. * @param int Session id (optional, default=0)
  1283. * @return string|bool Date with format long without day or false if there is no date
  1284. */
  1285. public static function get_first_connection_date_on_the_course(
  1286. $student_id,
  1287. $course_code,
  1288. $session_id = 0,
  1289. $convert_date = true
  1290. ) {
  1291. // protect data
  1292. $student_id = intval($student_id);
  1293. $course_code = Database::escape_string($course_code);
  1294. $session_id = intval($session_id);
  1295. $tbl_track_login = Database :: get_statistic_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
  1296. $sql = 'SELECT login_course_date FROM '.$tbl_track_login.'
  1297. WHERE user_id = '.$student_id.'
  1298. AND course_code = "'.$course_code.'"
  1299. AND session_id = '.$session_id.'
  1300. ORDER BY login_course_date ASC LIMIT 0,1';
  1301. $rs = Database::query($sql);
  1302. if (Database::num_rows($rs) > 0) {
  1303. if ($first_login_date = Database::result($rs, 0, 0)) {
  1304. if ($convert_date) {
  1305. return api_convert_and_format_date($first_login_date, DATE_FORMAT_SHORT);
  1306. } else {
  1307. return $first_login_date;
  1308. }
  1309. }
  1310. }
  1311. return false;
  1312. }
  1313. /**
  1314. * Get last user's connection date on the course
  1315. * @param int User id
  1316. * @param string Course code
  1317. * @param int Session id (optional, default=0)
  1318. * @return string|bool Date with format long without day or false if there is no date
  1319. */
  1320. public static function get_last_connection_date_on_the_course(
  1321. $student_id,
  1322. $course_code,
  1323. $session_id = 0,
  1324. $convert_date = true
  1325. ) {
  1326. // protect data
  1327. $student_id = intval($student_id);
  1328. $course_code = Database::escape_string($course_code);
  1329. $session_id = intval($session_id);
  1330. $tbl_track_e_access = Database :: get_statistic_table(TABLE_STATISTIC_TRACK_E_ACCESS);
  1331. $sql = 'SELECT access_date
  1332. FROM '.$tbl_track_e_access.'
  1333. WHERE access_user_id = '.$student_id.' AND
  1334. access_cours_code = "'.$course_code.'" AND
  1335. access_session_id = '.$session_id.'
  1336. ORDER BY access_date DESC
  1337. LIMIT 0,1';
  1338. $rs = Database::query($sql);
  1339. if (Database::num_rows($rs) > 0) {
  1340. if ($last_login_date = Database::result($rs, 0, 0)) {
  1341. if (empty($last_login_date) || $last_login_date == '0000-00-00 00:00:00') {
  1342. return false;
  1343. }
  1344. //$last_login_date_timestamp = api_strtotime($last_login_date, 'UTC');
  1345. //see #5736
  1346. $last_login_date_timestamp = api_strtotime($last_login_date);
  1347. $now = time();
  1348. //If the last connection is > than 7 days, the text is red
  1349. //345600 = 7 days in seconds
  1350. if ($now - $last_login_date_timestamp > 604800) {
  1351. if ($convert_date) {
  1352. $last_login_date = api_convert_and_format_date($last_login_date, DATE_FORMAT_SHORT);
  1353. $icon = api_is_allowed_to_edit() ? '<a href="'.api_get_path(REL_CODE_PATH).'announcements/announcements.php?action=add&remind_inactive='.$student_id.'" title="'.get_lang('RemindInactiveUser').'"><img src="'.api_get_path(WEB_IMG_PATH).'messagebox_warning.gif" /> </a>': null;
  1354. return $icon. Display::label($last_login_date, 'warning');
  1355. } else {
  1356. return $last_login_date;
  1357. }
  1358. } else {
  1359. if ($convert_date) {
  1360. return api_convert_and_format_date($last_login_date, DATE_FORMAT_SHORT);
  1361. } else {
  1362. return $last_login_date;
  1363. }
  1364. }
  1365. }
  1366. }
  1367. return false;
  1368. }
  1369. /**
  1370. * Get count of the connections to the course during a specified period
  1371. * @param string Course code
  1372. * @param int Session id (optional)
  1373. * @param int Datetime from which to collect data (defaults to 0)
  1374. * @param int Datetime to which to collect data (defaults to now)
  1375. * @return int count connections
  1376. */
  1377. public static function get_course_connections_count($course_code, $session_id = 0, $start = 0, $stop = null)
  1378. {
  1379. if ($start < 0) {
  1380. $start = 0;
  1381. }
  1382. if (!isset($stop) or ($stop < 0)) {
  1383. $stop = api_get_utc_datetime();
  1384. }
  1385. $start = Database::escape_string($start);
  1386. $stop = Database::escape_string($stop);
  1387. $month_filter = " AND login_course_date > '$start' AND login_course_date < '$stop' ";
  1388. $course_code = Database::escape_string($course_code);
  1389. $session_id = intval($session_id);
  1390. $count = 0;
  1391. $tbl_track_e_course_access = Database :: get_statistic_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
  1392. $sql = "SELECT count(*) as count_connections
  1393. FROM $tbl_track_e_course_access
  1394. WHERE
  1395. course_code = '$course_code' AND
  1396. session_id = $session_id
  1397. $month_filter";
  1398. $rs = Database::query($sql);
  1399. if (Database::num_rows($rs)>0) {
  1400. $row = Database::fetch_object($rs);
  1401. $count = $row->count_connections;
  1402. }
  1403. return $count;
  1404. }
  1405. /**
  1406. * Get count courses per student
  1407. * @param int Student id
  1408. * @param bool Include sessions (optional)
  1409. * @return int count courses
  1410. */
  1411. public static function count_course_per_student($user_id, $include_sessions = true)
  1412. {
  1413. $user_id = intval($user_id);
  1414. $tbl_course_rel_user = Database :: get_main_table(TABLE_MAIN_COURSE_USER);
  1415. $tbl_session_course_rel_user = Database :: get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
  1416. $sql = 'SELECT DISTINCT course_code
  1417. FROM ' . $tbl_course_rel_user . '
  1418. WHERE user_id = ' . $user_id.' AND relation_type<>'.COURSE_RELATION_TYPE_RRHH;
  1419. $rs = Database::query($sql);
  1420. $nb_courses = Database::num_rows($rs);
  1421. if ($include_sessions) {
  1422. $sql = 'SELECT DISTINCT course_code
  1423. FROM ' . $tbl_session_course_rel_user . '
  1424. WHERE id_user = ' . $user_id;
  1425. $rs = Database::query($sql);
  1426. $nb_courses += Database::num_rows($rs);
  1427. }
  1428. return $nb_courses;
  1429. }
  1430. /**
  1431. * Gets the score average from all tests in a course by student
  1432. *
  1433. * @param $student_id
  1434. * @param $course_code
  1435. * @param int $exercise_id
  1436. * @param null $session_id
  1437. * @param int $active_filter 2 for consider all tests
  1438. * 1 for active <> -1
  1439. * 0 for active <> 0
  1440. * @param int $into_lp 1 for all exercises
  1441. * 0 for without LP
  1442. * @internal param \Student $mixed id
  1443. * @internal param \Course $string code
  1444. * @internal param \Exercise $int id (optional), filtered by exercise
  1445. * @internal param \Session $int id (optional), if param $session_id is null it'll return results including sessions, 0 = session is not filtered
  1446. * @return string value (number %) Which represents a round integer about the score average.
  1447. */
  1448. public static function get_avg_student_exercise_score(
  1449. $student_id,
  1450. $course_code,
  1451. $exercise_id = 0,
  1452. $session_id = null,
  1453. $active_filter = 1,
  1454. $into_lp = 0
  1455. ) {
  1456. $course_code = Database::escape_string($course_code);
  1457. $course_info = api_get_course_info($course_code);
  1458. if (!empty($course_info)) {
  1459. // table definition
  1460. $tbl_course_quiz = Database::get_course_table(TABLE_QUIZ_TEST);
  1461. $tbl_stats_exercise = Database::get_statistic_table(TABLE_STATISTIC_TRACK_E_EXERCICES);
  1462. // Compose a filter based on optional exercise given
  1463. $condition_quiz = "";
  1464. if (!empty($exercise_id)) {
  1465. $exercise_id = intval($exercise_id);
  1466. $condition_quiz =" AND id = $exercise_id ";
  1467. }
  1468. // Compose a filter based on optional session id given
  1469. $condition_session = "";
  1470. if (isset($session_id)) {
  1471. $session_id = intval($session_id);
  1472. $condition_session = " AND session_id = $session_id ";
  1473. }
  1474. if ($active_filter == 1) {
  1475. $condition_active = 'AND active <> -1';
  1476. } elseif ($active_filter == 0) {
  1477. $condition_active = 'AND active <> 0';
  1478. } else {
  1479. $condition_active = '';
  1480. }
  1481. $condition_into_lp = '';
  1482. $select_lp_id = '';
  1483. if ($into_lp == 0) {
  1484. $condition_into_lp = 'AND orig_lp_id = 0 AND orig_lp_item_id = 0';
  1485. } else {
  1486. $select_lp_id = ', orig_lp_id as lp_id ';
  1487. }
  1488. $sql = "SELECT count(id) FROM $tbl_course_quiz
  1489. WHERE c_id = {$course_info['real_id']} $condition_active $condition_quiz ";
  1490. $count_quiz = Database::fetch_row(Database::query($sql));
  1491. if (!empty($count_quiz[0]) && !empty($student_id)) {
  1492. if (is_array($student_id)) {
  1493. $student_id = array_map('intval', $student_id);
  1494. $condition_user = " AND exe_user_id IN (".implode(',', $student_id).") ";
  1495. } else {
  1496. $student_id = intval($student_id);
  1497. $condition_user = " AND exe_user_id = '$student_id' ";
  1498. }
  1499. if (empty($exercise_id)) {
  1500. $sql = "SELECT id FROM $tbl_course_quiz
  1501. WHERE c_id = {$course_info['real_id']} $condition_active $condition_quiz";
  1502. $result = Database::query($sql);
  1503. $exercise_list = array();
  1504. $exercise_id = null;
  1505. if (Database::num_rows($result)) {
  1506. while ($row = Database::fetch_array($result)) {
  1507. $exercise_list[] = $row['id'];
  1508. }
  1509. }
  1510. if (!empty($exercise_list)) {
  1511. $exercise_id = implode("','",$exercise_list);
  1512. }
  1513. }
  1514. $count_quiz = Database::fetch_row(Database::query($sql));
  1515. $sql = "SELECT
  1516. SUM(exe_result/exe_weighting*100) as avg_score,
  1517. COUNT(*) as num_attempts
  1518. $select_lp_id
  1519. FROM $tbl_stats_exercise
  1520. WHERE
  1521. exe_exo_id IN ('".$exercise_id."')
  1522. $condition_user AND
  1523. status = '' AND
  1524. exe_cours_id = '$course_code'
  1525. $condition_session
  1526. $condition_into_lp
  1527. ORDER BY exe_date DESC";
  1528. $res = Database::query($sql);
  1529. $row = Database::fetch_array($res);
  1530. $quiz_avg_score = null;
  1531. if (!empty($row['avg_score'])) {
  1532. $quiz_avg_score = round($row['avg_score'],2);
  1533. }
  1534. if(!empty($row['num_attempts'])) {
  1535. $quiz_avg_score = round($quiz_avg_score / $row['num_attempts'], 2);
  1536. }
  1537. if (is_array($student_id)) {
  1538. $quiz_avg_score = round($quiz_avg_score / count($student_id), 2);
  1539. }
  1540. if ($into_lp == 0) {
  1541. return $quiz_avg_score;
  1542. } else {
  1543. if (!empty($row['lp_id'])) {
  1544. $tbl_lp = Database::get_course_table(TABLE_LP_MAIN);
  1545. $tbl_course = Database::get_main_table(TABLE_MAIN_COURSE);
  1546. $sql = "SELECT lp.name
  1547. FROM $tbl_lp as lp, $tbl_course as c
  1548. WHERE
  1549. c.code = '$course_code' AND
  1550. lp.id = ".$row['lp_id']." AND
  1551. lp.c_id = c.id
  1552. LIMIT 1;
  1553. ";
  1554. $result = Database::query($sql);
  1555. $row_lp = Database::fetch_row($result);
  1556. $lp_name = $row_lp[0];
  1557. return array($quiz_avg_score, $lp_name);
  1558. } else {
  1559. return array($quiz_avg_score, null);
  1560. }
  1561. }
  1562. }
  1563. }
  1564. return null;
  1565. }
  1566. /**
  1567. * Get count student's exercise COMPLETED attempts
  1568. * @param $student_id
  1569. * @param $course_code
  1570. * @param $exercise_id
  1571. * @param int $lp_id
  1572. * @param int $lp_item_id
  1573. * @param int $session_id
  1574. * @param int $find_all_lp 0 = just LP specified
  1575. * 1 = LP specified or whitout LP,
  1576. * 2 = all rows
  1577. * @internal param \Student $int id
  1578. * @internal param \Course $string code
  1579. * @internal param \Exercise $int id
  1580. * @internal param \Learning $int path id (optional), for showing attempts inside a learning path $lp_id and $lp_item_id params are required.
  1581. * @internal param \Learning $int path item id (optional), for showing attempts inside a learning path $lp_id and $lp_item_id params are required.
  1582. * @return int count of attempts
  1583. */
  1584. public static function count_student_exercise_attempts(
  1585. $student_id,
  1586. $course_code,
  1587. $exercise_id,
  1588. $lp_id = 0,
  1589. $lp_item_id = 0,
  1590. $session_id = 0,
  1591. $find_all_lp = 0
  1592. ) {
  1593. $course_code = Database::escape_string($course_code);
  1594. $student_id = intval($student_id);
  1595. $exercise_id = intval($exercise_id);
  1596. $session_id = intval($session_id);
  1597. $lp_id = intval($lp_id);
  1598. $lp_item_id = intval($lp_item_id);
  1599. $tbl_stats_exercices = Database :: get_statistic_table(TABLE_STATISTIC_TRACK_E_EXERCICES);
  1600. $sql = "SELECT COUNT(ex.exe_id) as essais FROM $tbl_stats_exercices AS ex
  1601. WHERE ex.exe_cours_id = '$course_code'
  1602. AND ex.exe_exo_id = $exercise_id
  1603. AND status = ''
  1604. AND exe_user_id= $student_id
  1605. AND session_id = $session_id ";
  1606. if ($find_all_lp == 1) {
  1607. $sql .= "AND (orig_lp_id = $lp_id OR orig_lp_id = 0)
  1608. AND (orig_lp_item_id = $lp_item_id OR orig_lp_item_id = 0)";
  1609. } elseif ($find_all_lp == 0) {
  1610. $sql .= "AND orig_lp_id = $lp_id
  1611. AND orig_lp_item_id = $lp_item_id";
  1612. }
  1613. $rs = Database::query($sql);
  1614. $row = Database::fetch_row($rs);
  1615. $count_attempts = $row[0];
  1616. return $count_attempts;
  1617. }
  1618. /**
  1619. * Get count student's exercise progress
  1620. *
  1621. * @param array $exercise_list
  1622. * @param int $user_id
  1623. * @param string $course_code
  1624. * @param int $session_id
  1625. */
  1626. public static function get_exercise_student_progress($exercise_list, $user_id, $course_code, $session_id)
  1627. {
  1628. $course_code = Database::escape_string($course_code);
  1629. $user_id = intval($user_id);
  1630. $session_id = intval($session_id);
  1631. if (empty($exercise_list)) {
  1632. return '0%';
  1633. }
  1634. $tbl_stats_exercices = Database :: get_statistic_table(TABLE_STATISTIC_TRACK_E_EXERCICES);
  1635. $exercise_list = array_keys($exercise_list);
  1636. $exercise_list = array_map('intval', $exercise_list);
  1637. $exercise_list_imploded = implode("' ,'", $exercise_list);
  1638. $sql = "SELECT COUNT(DISTINCT ex.exe_exo_id)
  1639. FROM $tbl_stats_exercices AS ex
  1640. WHERE
  1641. ex.exe_cours_id = '$course_code' AND
  1642. ex.session_id = $session_id AND
  1643. ex.exe_user_id = $user_id AND
  1644. ex.exe_exo_id IN ('$exercise_list_imploded') ";
  1645. $rs = Database::query($sql);
  1646. $count = 0;
  1647. if ($rs) {
  1648. $row = Database::fetch_row($rs);
  1649. $count = $row[0];
  1650. }
  1651. $count = ($count != 0 ) ? 100*round(intval($count)/count($exercise_list), 2) .'%' : '0%';
  1652. return $count;
  1653. }
  1654. /**
  1655. * @param array $exercise_list
  1656. * @param int $user_id
  1657. * @param string $course_code
  1658. * @param int $session_id
  1659. * @return string
  1660. */
  1661. public static function get_exercise_student_average_best_attempt($exercise_list, $user_id, $course_code, $session_id)
  1662. {
  1663. $result = 0;
  1664. if (!empty($exercise_list)) {
  1665. foreach ($exercise_list as $exercise_data) {
  1666. $exercise_id = $exercise_data['id'];
  1667. $best_attempt = get_best_attempt_exercise_results_per_user(
  1668. $user_id,
  1669. $exercise_id,
  1670. $course_code,
  1671. $session_id
  1672. );
  1673. if (!empty($best_attempt) && !empty($best_attempt['exe_weighting'])) {
  1674. $result += $best_attempt['exe_result']/$best_attempt['exe_weighting'];
  1675. }
  1676. }
  1677. $result = $result / count($exercise_list);
  1678. $result = round($result, 2) * 100;
  1679. }
  1680. return $result.'%';
  1681. }
  1682. /**
  1683. * get teacher progress by course and session
  1684. * @param int course id
  1685. * @param int session id
  1686. * @return array
  1687. */
  1688. static function get_teachers_progress_by_course($courseId, $sessionId)
  1689. {
  1690. $course = api_get_course_info_by_id($courseId);
  1691. $sessionId = intval($sessionId);
  1692. $courseId = intval($courseId);
  1693. //get teachers
  1694. $sql = "SELECT scu.id_session, scu.id_user, s.name
  1695. FROM session_rel_course_rel_user scu, session s
  1696. WHERE
  1697. scu.id_session = s.id
  1698. AND scu.status = 2
  1699. AND scu.visibility = 1
  1700. AND scu.course_code = '%s'
  1701. AND scu.id_session = %s";
  1702. $query = sprintf($sql,$course['code'], $sessionId);
  1703. $rs = Database::query($query);
  1704. $teachers = array();
  1705. while ($teacher = Database::fetch_array($rs,'ASSOC')) {
  1706. $teachers[] = $teacher;
  1707. }
  1708. $data = array();
  1709. foreach ($teachers as $teacher) {
  1710. //total documents added
  1711. $sql = "SELECT count(*) as total
  1712. FROM c_item_property
  1713. WHERE lastedit_type = 'DocumentAdded'
  1714. AND c_id = %s
  1715. AND insert_user_id = %s
  1716. AND id_session = %s";
  1717. $query = sprintf($sql,
  1718. $courseId,
  1719. $teacher['id_user'],
  1720. $teacher['id_session']
  1721. );
  1722. $rs = Database::query($query);
  1723. $totalDocuments = 0;
  1724. if ($rs) {
  1725. $row = Database::fetch_row($rs);
  1726. $totalDocuments = $row[0];
  1727. }
  1728. //total links added
  1729. $sql = "SELECT count(*) as total
  1730. FROM c_item_property
  1731. WHERE lastedit_type = 'LinkAdded'
  1732. AND c_id = %s
  1733. AND insert_user_id = %s
  1734. AND id_session = %s";
  1735. $query = sprintf($sql,
  1736. $courseId,
  1737. $teacher['id_user'],
  1738. $teacher['id_session']
  1739. );
  1740. $rs = Database::query($query);
  1741. $totalLinks = 0;
  1742. if ($rs) {
  1743. $row = Database::fetch_row($rs);
  1744. $totalLinks = $row[0];
  1745. }
  1746. //total forums added
  1747. $sql = "SELECT count(*) as total
  1748. FROM c_item_property
  1749. WHERE lastedit_type = 'ForumthreadVisible'
  1750. AND c_id = %s
  1751. AND insert_user_id = %s
  1752. AND id_session = %s";
  1753. $query = sprintf($sql,
  1754. $courseId,
  1755. $teacher['id_user'],
  1756. $teacher['id_session']
  1757. );
  1758. $rs = Database::query($query);
  1759. $totalForums = 0;
  1760. if ($rs) {
  1761. $row = Database::fetch_row($rs);
  1762. $totalForums = $row[0];
  1763. }
  1764. //total wikis added
  1765. $sql = "SELECT COUNT(DISTINCT(ref)) as total
  1766. FROM c_item_property
  1767. WHERE lastedit_type = 'WikiAdded'
  1768. AND c_id = %s
  1769. AND insert_user_id = %s
  1770. AND id_session = %s";
  1771. $query = sprintf($sql,
  1772. $courseId,
  1773. $teacher['id_user'],
  1774. $teacher['id_session']
  1775. );
  1776. $rs = Database::query($query);
  1777. $totalWikis = 0;
  1778. if ($rs) {
  1779. $row = Database::fetch_row($rs);
  1780. $totalWikis = $row[0];
  1781. }
  1782. //total works added
  1783. $sql = "SELECT COUNT(*) as total
  1784. FROM c_item_property
  1785. WHERE lastedit_type = 'DirectoryCreated'
  1786. AND tool = 'work'
  1787. AND c_id = %s
  1788. AND insert_user_id = %s
  1789. AND id_session = %s";
  1790. $query = sprintf($sql,
  1791. $courseId,
  1792. $teacher['id_user'],
  1793. $teacher['id_session']
  1794. );
  1795. $rs = Database::query($query);
  1796. $totalWorks = 0;
  1797. if ($rs) {
  1798. $row = Database::fetch_row($rs);
  1799. $totalWorks = $row[0];
  1800. }
  1801. //total announcements added
  1802. $sql = "SELECT COUNT(*) as total
  1803. FROM c_item_property
  1804. WHERE lastedit_type = 'AnnouncementAdded'
  1805. AND c_id = %s
  1806. AND insert_user_id = %s
  1807. AND id_session = %s";
  1808. $query = sprintf($sql,
  1809. $courseId,
  1810. $teacher['id_user'],
  1811. $teacher['id_session']
  1812. );
  1813. $rs = Database::query($query);
  1814. $totalAnnouncements = 0;
  1815. if ($rs) {
  1816. $row = Database::fetch_row($rs);
  1817. $totalAnnouncements = $row[0];
  1818. }
  1819. $tutor = api_get_user_info($teacher['id_user']);
  1820. $data[] = array(
  1821. 'course' => $course['title'],
  1822. 'session' => $teacher['name'],
  1823. 'tutor' => $tutor['username'] . ' - ' . $tutor['lastname'] . ' ' . $tutor['firstname'],
  1824. 'documents' => $totalDocuments,
  1825. 'links' => $totalLinks,
  1826. 'forums' => $totalForums,
  1827. 'works' => $totalWorks,
  1828. 'wikis' => $totalWikis,
  1829. 'announcements' => $totalAnnouncements,
  1830. );
  1831. }
  1832. return $data;
  1833. }
  1834. /**
  1835. * Returns the average student progress in the learning paths of the given
  1836. * course.
  1837. * @param int|array $student_id
  1838. * @param string $course_code
  1839. * @param array $lp_ids Limit average to listed lp ids
  1840. * @param int $session_id Session id (optional),
  1841. * if parameter $session_id is null(default) it'll return results including
  1842. * sessions, 0 = session is not filtered
  1843. * @param bool $return_array Will return an array of the type:
  1844. * [sum_of_progresses, number] if it is set to true
  1845. * @return double Average progress of the user in this course
  1846. */
  1847. public static function get_avg_student_progress(
  1848. $student_id,
  1849. $course_code = null,
  1850. $lp_ids = array(),
  1851. $session_id = null,
  1852. $return_array = false
  1853. ) {
  1854. $conditions = array();
  1855. $session_id = intval($session_id);
  1856. // Get the information of the course.
  1857. $course_info = api_get_course_info($course_code);
  1858. if (!empty($course_info)) {
  1859. $conditions[] = " c_id = {$course_info['real_id']} ";
  1860. }
  1861. // table definition
  1862. $tbl_course_lp_view = Database :: get_course_table(TABLE_LP_VIEW);
  1863. // Compose a filter based on optional learning paths list given
  1864. $condition_lp = null;
  1865. if (!empty($lp_ids)) {
  1866. if (count($lp_ids) > 0) {
  1867. $lp_ids = array_map('intval', $lp_ids);
  1868. $conditions[] = " lp_view.lp_id IN(".implode(',', $lp_ids).") ";
  1869. }
  1870. }
  1871. // If there is at least one learning path and one student.
  1872. if (!empty($student_id)) {
  1873. if (is_array($student_id)) {
  1874. $student_id = array_map('intval', $student_id);
  1875. $conditions[] = " lp_view.user_id IN (".implode(',', $student_id).") ";
  1876. } else {
  1877. $student_id = intval($student_id);
  1878. $conditions[] = " lp_view.user_id = '$student_id' ";
  1879. }
  1880. if (!empty($session_id)) {
  1881. $conditions[] = " session_id = $session_id ";
  1882. }
  1883. $conditionToString = implode('AND', $conditions);
  1884. // Get last view for each student (in case of multi-attempt)
  1885. // Also filter on LPs of this session
  1886. $sql = " SELECT
  1887. MAX(view_count),
  1888. AVG(progress) average,
  1889. SUM(progress) sum_progress,
  1890. count(progress) count_progress
  1891. FROM $tbl_course_lp_view lp_view
  1892. WHERE
  1893. $conditionToString
  1894. GROUP BY lp_id";
  1895. $result = Database::query($sql);
  1896. $row = Database::fetch_array($result, 'ASSOC');
  1897. if (!$return_array) {
  1898. $avg_progress = round($row['average'], 1);
  1899. return $avg_progress;
  1900. } else {
  1901. return array($row['sum_progress'], $row['count_progress']);
  1902. }
  1903. }
  1904. }
  1905. /**
  1906. * This function gets:
  1907. * 1. The score average from all SCORM Test items in all LP in a course-> All the answers / All the max scores.
  1908. * 2. The score average from all Tests (quiz) in all LP in a course-> All the answers / All the max scores.
  1909. * 3. And finally it will return the average between 1. and 2.
  1910. * @todo improve performance, when loading 1500 users with 20 lps the script dies
  1911. * This function does not take the results of a Test out of a LP
  1912. *
  1913. * @param mixed $student_id Array of user ids or an user id
  1914. * @param string $course_code
  1915. * @param array $lp_ids List of LP ids
  1916. * @param int $session_id Session id (optional),
  1917. * if param $session_id is null(default) it'll return results
  1918. * including sessions, 0 = session is not filtered
  1919. * @param bool $return_array Returns an array of the
  1920. * type [sum_score, num_score] if set to true
  1921. * @param bool $get_only_latest_attempt_results get only the latest attempts or ALL attempts
  1922. *
  1923. * @return string Value (number %) Which represents a round integer explain in got in 3.
  1924. */
  1925. public static function get_avg_student_score(
  1926. $student_id,
  1927. $course_code,
  1928. $lp_ids = array(),
  1929. $session_id = null,
  1930. $return_array = false,
  1931. $get_only_latest_attempt_results = false
  1932. ) {
  1933. $debug = false;
  1934. if (empty($lp_ids)) {
  1935. $debug = false;
  1936. }
  1937. if ($debug) echo '<h1>Tracking::get_avg_student_score</h1>';
  1938. $tbl_stats_exercices = Database :: get_statistic_table(TABLE_STATISTIC_TRACK_E_EXERCICES);
  1939. $tbl_stats_attempts = Database :: get_statistic_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
  1940. $course = api_get_course_info($course_code);
  1941. if (!empty($course)) {
  1942. // Get course tables names
  1943. $tbl_quiz_questions = Database :: get_course_table(TABLE_QUIZ_QUESTION);
  1944. $lp_table = Database :: get_course_table(TABLE_LP_MAIN);
  1945. $lp_item_table = Database :: get_course_table(TABLE_LP_ITEM);
  1946. $lp_view_table = Database :: get_course_table(TABLE_LP_VIEW);
  1947. $lp_item_view_table = Database :: get_course_table(TABLE_LP_ITEM_VIEW);
  1948. $course_id = $course['real_id'];
  1949. // Compose a filter based on optional learning paths list given
  1950. $condition_lp = "";
  1951. if (count($lp_ids) > 0) {
  1952. $condition_lp =" AND id IN(".implode(',',$lp_ids).") ";
  1953. }
  1954. // Compose a filter based on optional session id
  1955. $session_id = intval($session_id);
  1956. if (count($lp_ids) > 0) {
  1957. $condition_session = " AND session_id = $session_id ";
  1958. } else {
  1959. $condition_session = " WHERE session_id = $session_id ";
  1960. }
  1961. // Check the real number of LPs corresponding to the filter in the
  1962. // database (and if no list was given, get them all)
  1963. if (empty($session_id)) {
  1964. $sql = "SELECT DISTINCT(id), use_max_score FROM $lp_table
  1965. WHERE c_id = $course_id AND session_id = 0 $condition_lp ";
  1966. } else {
  1967. $sql = "SELECT DISTINCT(id), use_max_score FROM $lp_table
  1968. WHERE c_id = $course_id $condition_lp ";
  1969. }
  1970. $res_row_lp = Database::query($sql);
  1971. $count_row_lp = Database::num_rows($res_row_lp);
  1972. $lp_list = $use_max_score = array();
  1973. while ($row_lp = Database::fetch_array($res_row_lp)) {
  1974. $lp_list[] = $row_lp['id'];
  1975. $use_max_score[$row_lp['id']] = $row_lp['use_max_score'];
  1976. }
  1977. if ($debug) {
  1978. echo 'Use max score or not list '; var_dump($use_max_score);
  1979. }
  1980. // prepare filter on users
  1981. if (is_array($student_id)) {
  1982. array_walk($student_id, 'intval');
  1983. $condition_user1 =" AND user_id IN (".implode(',', $student_id).") ";
  1984. } else {
  1985. $condition_user1 =" AND user_id = $student_id ";
  1986. }
  1987. if ($count_row_lp > 0 && !empty($student_id)) {
  1988. // Getting latest LP result for a student
  1989. //@todo problem when a course have more than 1500 users
  1990. $sql = "SELECT MAX(view_count) as vc, id, progress, lp_id, user_id
  1991. FROM $lp_view_table
  1992. WHERE
  1993. c_id = $course_id AND
  1994. lp_id IN (".implode(',', $lp_list).")
  1995. $condition_user1 AND
  1996. session_id = $session_id
  1997. GROUP BY lp_id, user_id";
  1998. if ($debug) echo $sql;
  1999. $rs_last_lp_view_id = Database::query($sql);
  2000. $global_result = 0;
  2001. if (Database::num_rows($rs_last_lp_view_id) > 0) {
  2002. // Cycle through each line of the results (grouped by lp_id, user_id)
  2003. while ($row_lp_view = Database::fetch_array($rs_last_lp_view_id)) {
  2004. $count_items = 0;
  2005. $lp_partial_total = 0;
  2006. $list = array();
  2007. $lp_view_id = $row_lp_view['id'];
  2008. $lp_id = $row_lp_view['lp_id'];
  2009. $user_id = $row_lp_view['user_id'];
  2010. if ($debug) echo '<h2>LP id '.$lp_id.'</h2>';
  2011. if ($get_only_latest_attempt_results) {
  2012. //Getting lp_items done by the user
  2013. $sql = "SELECT DISTINCT lp_item_id
  2014. FROM $lp_item_view_table
  2015. WHERE
  2016. c_id = $course_id AND
  2017. lp_view_id = $lp_view_id
  2018. ORDER BY lp_item_id";
  2019. $res_lp_item = Database::query($sql);
  2020. while ($row_lp_item = Database::fetch_array($res_lp_item,'ASSOC')) {
  2021. $my_lp_item_id = $row_lp_item['lp_item_id'];
  2022. // Getting the most recent attempt
  2023. $sql = "SELECT lp_iv.id as lp_item_view_id,
  2024. lp_iv.score as score,
  2025. lp_i.max_score,
  2026. lp_iv.max_score as max_score_item_view,
  2027. lp_i.path,
  2028. lp_i.item_type,
  2029. lp_i.id as iid
  2030. FROM $lp_item_view_table as lp_iv
  2031. INNER JOIN $lp_item_table as lp_i
  2032. ON lp_i.id = lp_iv.lp_item_id AND
  2033. lp_iv.c_id = $course_id AND
  2034. lp_i.c_id = $course_id AND
  2035. (lp_i.item_type='sco' OR lp_i.item_type='".TOOL_QUIZ."')
  2036. WHERE
  2037. lp_item_id = $my_lp_item_id AND
  2038. lp_view_id = $lp_view_id
  2039. ORDER BY view_count DESC
  2040. LIMIT 1";
  2041. $res_lp_item_result = Database::query($sql);
  2042. while ($row_max_score = Database::fetch_array($res_lp_item_result,'ASSOC')) {
  2043. $list[]= $row_max_score;
  2044. }
  2045. }
  2046. } else {
  2047. // For the currently analysed view, get the score and
  2048. // max_score of each item if it is a sco or a TOOL_QUIZ
  2049. $sql = "SELECT
  2050. lp_iv.id as lp_item_view_id,
  2051. lp_iv.score as score,
  2052. lp_i.max_score,
  2053. lp_iv.max_score as max_score_item_view,
  2054. lp_i.path,
  2055. lp_i.item_type,
  2056. lp_i.id as iid
  2057. FROM $lp_item_view_table as lp_iv
  2058. INNER JOIN $lp_item_table as lp_i
  2059. ON lp_i.id = lp_iv.lp_item_id AND
  2060. lp_iv.c_id = $course_id AND
  2061. lp_i.c_id = $course_id AND
  2062. (lp_i.item_type='sco' OR lp_i.item_type='".TOOL_QUIZ."')
  2063. WHERE lp_view_id = $lp_view_id ";
  2064. if ($debug) echo $sql.'<br />';
  2065. $res_max_score = Database::query($sql);
  2066. while ($row_max_score = Database::fetch_array($res_max_score,'ASSOC')) {
  2067. $list[]= $row_max_score;
  2068. }
  2069. }
  2070. // Go through each scorable element of this view
  2071. $score_of_scorm_calculate = 0;
  2072. foreach ($list as $row_max_score) {
  2073. // Came from the original lp_item
  2074. $max_score = $row_max_score['max_score'];
  2075. // Came from the lp_item_view
  2076. $max_score_item_view = $row_max_score['max_score_item_view'];
  2077. $score = $row_max_score['score'];
  2078. if ($debug) echo '<h3>Item Type: ' .$row_max_score['item_type'].'</h3>';
  2079. if ($row_max_score['item_type'] == 'sco') {
  2080. /* Check if it is sco (easier to get max_score)
  2081. when there's no max score, we assume 100 as the max score,
  2082. as the SCORM 1.2 says that the value should always be between 0 and 100.
  2083. */
  2084. if ($max_score == 0 || is_null($max_score) || $max_score == '') {
  2085. // Chamilo style
  2086. if ($use_max_score[$lp_id]) {
  2087. $max_score = 100;
  2088. } else {
  2089. // Overwrites max score = 100 to use the one that came in the lp_item_view see BT#1613
  2090. $max_score = $max_score_item_view;
  2091. }
  2092. }
  2093. // Avoid division by zero errors
  2094. if (!empty($max_score)) {
  2095. $lp_partial_total += $score/$max_score;
  2096. }
  2097. if ($debug) echo '<b>$lp_partial_total, $score, $max_score '.$lp_partial_total.' '.$score.' '.$max_score.'</b><br />';
  2098. } else {
  2099. // Case of a TOOL_QUIZ element
  2100. $item_id = $row_max_score['iid'];
  2101. $item_path = $row_max_score['path'];
  2102. $lp_item_view_id = $row_max_score['lp_item_view_id'];
  2103. // Get last attempt to this exercise through
  2104. // the current lp for the current user
  2105. $sql = "SELECT exe_id
  2106. FROM $tbl_stats_exercices
  2107. WHERE
  2108. exe_exo_id = '$item_path' AND
  2109. exe_user_id = $user_id AND
  2110. orig_lp_item_id = $item_id AND
  2111. orig_lp_item_view_id = $lp_item_view_id AND
  2112. exe_cours_id = '$course_code' AND
  2113. session_id = $session_id AND
  2114. status = ''
  2115. ORDER BY exe_date DESC
  2116. LIMIT 1";
  2117. if ($debug) echo $sql .'<br />';
  2118. $result_last_attempt = Database::query($sql);
  2119. $num = Database :: num_rows($result_last_attempt);
  2120. if ($num > 0 ) {
  2121. $id_last_attempt = Database :: result($result_last_attempt, 0, 0);
  2122. if ($debug) echo $id_last_attempt.'<br />';
  2123. // Within the last attempt number tracking, get the sum of
  2124. // the max_scores of all questions that it was
  2125. // made of (we need to make this call dynamic because of random questions selection)
  2126. $sql = "SELECT SUM(t.ponderation) as maxscore FROM
  2127. (
  2128. SELECT DISTINCT
  2129. question_id,
  2130. marks,
  2131. ponderation
  2132. FROM $tbl_stats_attempts AS at
  2133. INNER JOIN $tbl_quiz_questions AS q
  2134. ON (q.id = at.question_id)
  2135. WHERE
  2136. exe_id ='$id_last_attempt' AND
  2137. q.c_id = $course_id
  2138. )
  2139. AS t";
  2140. if ($debug) echo '$sql: '.$sql.' <br />';
  2141. $res_max_score_bis = Database::query($sql);
  2142. $row_max_score_bis = Database::fetch_array($res_max_score_bis);
  2143. if (!empty($row_max_score_bis['maxscore'])) {
  2144. $max_score = $row_max_score_bis['maxscore'];
  2145. }
  2146. if (!empty($max_score) && floatval($max_score) > 0) {
  2147. $lp_partial_total += $score/$max_score;
  2148. }
  2149. if ($debug) echo '$lp_partial_total, $score, $max_score <b>'.$lp_partial_total.' '.$score.' '.$max_score.'</b><br />';
  2150. }
  2151. }
  2152. if (in_array($row_max_score['item_type'], array('quiz','sco'))) {
  2153. // Normal way
  2154. if ($use_max_score[$lp_id]) {
  2155. $count_items++;
  2156. } else {
  2157. if ($max_score != '') {
  2158. $count_items++;
  2159. }
  2160. }
  2161. if ($debug) echo '$count_items: '.$count_items;
  2162. }
  2163. } //end for
  2164. $score_of_scorm_calculate += $count_items ? (($lp_partial_total / $count_items) * 100) : 0;
  2165. if ($debug) echo '<h3>$count_items '.$count_items.'</h3>';
  2166. if ($debug) echo '<h3>$score_of_scorm_calculate '.$score_of_scorm_calculate.'</h3>';
  2167. $global_result += $score_of_scorm_calculate;
  2168. if ($debug) echo '<h3>$global_result '.$global_result.'</h3>';
  2169. } // end while
  2170. }
  2171. $lp_with_quiz = 0;
  2172. foreach ($lp_list as $lp_id) {
  2173. // Check if LP have a score we assume that all SCO have an score
  2174. $sql = "SELECT count(id) as count
  2175. FROM $lp_item_table
  2176. WHERE
  2177. c_id = $course_id AND
  2178. (item_type = 'quiz' OR item_type = 'sco') AND
  2179. lp_id = ".$lp_id;
  2180. if ($debug) echo $sql;
  2181. $result_have_quiz = Database::query($sql);
  2182. if (Database::num_rows($result_have_quiz) > 0 ) {
  2183. $row = Database::fetch_array($result_have_quiz,'ASSOC');
  2184. if (is_numeric($row['count']) && $row['count'] != 0) {
  2185. $lp_with_quiz++;
  2186. }
  2187. }
  2188. }
  2189. if ($debug) echo '<h3>$lp_with_quiz '.$lp_with_quiz.' </h3>';
  2190. if ($debug) echo '<h3>Final return</h3>';
  2191. if ($lp_with_quiz != 0) {
  2192. if (!$return_array) {
  2193. $score_of_scorm_calculate = round(($global_result/$lp_with_quiz),2);
  2194. if ($debug) var_dump($score_of_scorm_calculate);
  2195. if (empty($lp_ids)) {
  2196. if ($debug) echo '<h2>All lps fix: '.$score_of_scorm_calculate.'</h2>';
  2197. }
  2198. return $score_of_scorm_calculate;
  2199. } else {
  2200. if ($debug) var_dump($global_result, $lp_with_quiz);
  2201. return array($global_result, $lp_with_quiz);
  2202. }
  2203. } else {
  2204. return '-';
  2205. }
  2206. }
  2207. }
  2208. return null;
  2209. }
  2210. /**
  2211. * This function gets:
  2212. * 1. The score average from all SCORM Test items in all LP in a course-> All the answers / All the max scores.
  2213. * 2. The score average from all Tests (quiz) in all LP in a course-> All the answers / All the max scores.
  2214. * 3. And finally it will return the average between 1. and 2.
  2215. * This function does not take the results of a Test out of a LP
  2216. *
  2217. * @param int|array Array of user ids or an user id
  2218. * @param string Course code
  2219. * @param array List of LP ids
  2220. * @param int Session id (optional), if param $session_id is null(default) it'll return results including sessions, 0 = session is not filtered
  2221. * @param bool Returns an array of the type [sum_score, num_score] if set to true
  2222. * @param bool get only the latest attempts or ALL attempts
  2223. * @return string Value (number %) Which represents a round integer explain in got in 3.
  2224. */
  2225. public static function getAverageStudentScore(
  2226. $student_id,
  2227. $course_code = null,
  2228. $lp_ids = array(),
  2229. $session_id = null
  2230. ) {
  2231. if (empty($student_id)) {
  2232. return 0;
  2233. }
  2234. $conditions = array();
  2235. if (!empty($course_code)) {
  2236. $course = api_get_course_info($course_code);
  2237. $courseId = $course['real_id'];
  2238. $conditions[] = " c_id = $courseId";
  2239. }
  2240. // Get course tables names
  2241. $lp_table = Database :: get_course_table(TABLE_LP_MAIN);
  2242. $lp_item_table = Database :: get_course_table(TABLE_LP_ITEM);
  2243. $lp_view_table = Database :: get_course_table(TABLE_LP_VIEW);
  2244. $lp_item_view_table = Database :: get_course_table(TABLE_LP_ITEM_VIEW);
  2245. // Compose a filter based on optional learning paths list given
  2246. if (!empty($lp_ids) && count($lp_ids) > 0) {
  2247. $conditions[] = " id IN(".implode(',', $lp_ids).") ";
  2248. }
  2249. // Compose a filter based on optional session id
  2250. $session_id = intval($session_id);
  2251. if (!empty($session_id)) {
  2252. $conditions[] = " session_id = $session_id ";
  2253. }
  2254. if (is_array($student_id)) {
  2255. array_walk($student_id, 'intval');
  2256. $conditions[] =" lp_view.user_id IN (".implode(',', $student_id).") ";
  2257. } else {
  2258. $conditions[] =" lp_view.user_id = $student_id ";
  2259. }
  2260. $conditionsToString = implode('AND ', $conditions);
  2261. $sql = "SELECT SUM(lp_iv.score) sum_score,
  2262. SUM(lp_i.max_score) sum_max_score,
  2263. count(*) as count
  2264. FROM $lp_table as lp
  2265. INNER JOIN $lp_item_table as lp_i
  2266. ON lp.id = lp_id AND lp.c_id = lp_i.c_id
  2267. INNER JOIN $lp_view_table as lp_view
  2268. ON lp_view.lp_id = lp_i.lp_id AND lp_view.c_id = lp_i.c_id
  2269. INNER JOIN $lp_item_view_table as lp_iv
  2270. ON lp_i.id = lp_iv.lp_item_id AND lp_view.c_id = lp_iv.c_id AND lp_iv.lp_view_id = lp_view.id
  2271. WHERE (lp_i.item_type='sco' OR lp_i.item_type='".TOOL_QUIZ."') AND
  2272. $conditionsToString
  2273. ";
  2274. $result = Database::query($sql);
  2275. $row = Database::fetch_array($result, 'ASSOC');
  2276. if (empty($row['sum_max_score'])) {
  2277. return 0;
  2278. }
  2279. return ($row['sum_score'] / $row['sum_max_score'])*100;
  2280. }
  2281. /**
  2282. * This function gets time spent in learning path for a student inside a course
  2283. * @param int|array Student id(s)
  2284. * @param string Course code
  2285. * @param array Limit average to listed lp ids
  2286. * @param int Session id (optional), if param $session_id is null(default) it'll return results including sessions, 0 = session is not filtered
  2287. * @return int Total time
  2288. */
  2289. public static function get_time_spent_in_lp($student_id, $course_code, $lp_ids = array(), $session_id = null)
  2290. {
  2291. $course = CourseManager :: get_course_information($course_code);
  2292. $student_id = intval($student_id);
  2293. $total_time = 0;
  2294. if (!empty($course)) {
  2295. $lp_table = Database :: get_course_table(TABLE_LP_MAIN);
  2296. $t_lpv = Database :: get_course_table(TABLE_LP_VIEW);
  2297. $t_lpiv = Database :: get_course_table(TABLE_LP_ITEM_VIEW);
  2298. $course_id = $course['real_id'];
  2299. // Compose a filter based on optional learning paths list given
  2300. $condition_lp = "";
  2301. if(count($lp_ids) > 0) {
  2302. $condition_lp =" AND id IN(".implode(',',$lp_ids).") ";
  2303. }
  2304. // Compose a filter based on optional session id
  2305. $condition_session = "";
  2306. $session_id = intval($session_id);
  2307. if (isset($session_id)) {
  2308. $condition_session = " AND session_id = $session_id ";
  2309. }
  2310. // Check the real number of LPs corresponding to the filter in the
  2311. // database (and if no list was given, get them all)
  2312. //$res_row_lp = Database::query("SELECT DISTINCT(id) FROM $lp_table $condition_lp $condition_session");
  2313. $res_row_lp = Database::query("SELECT DISTINCT(id) FROM $lp_table WHERE c_id = $course_id $condition_lp");
  2314. $count_row_lp = Database::num_rows($res_row_lp);
  2315. // calculates time
  2316. if ($count_row_lp > 0) {
  2317. while ($row_lp = Database::fetch_array($res_row_lp)) {
  2318. $lp_id = intval($row_lp['id']);
  2319. $sql = 'SELECT SUM(total_time)
  2320. FROM '.$t_lpiv.' AS item_view
  2321. INNER JOIN '.$t_lpv.' AS view
  2322. ON item_view.lp_view_id = view.id
  2323. WHERE
  2324. item_view.c_id = '.$course_id.' AND
  2325. view.c_id = '.$course_id.' AND
  2326. view.lp_id = '.$lp_id.'
  2327. AND view.user_id = '.$student_id.' AND
  2328. session_id = '.$session_id;
  2329. $rs = Database::query($sql);
  2330. if (Database :: num_rows($rs) > 0) {
  2331. $total_time += Database :: result($rs, 0, 0);
  2332. }
  2333. }
  2334. }
  2335. }
  2336. return $total_time;
  2337. }
  2338. /**
  2339. * This function gets last connection time to one learning path
  2340. * @param int|array Student id(s)
  2341. * @param string Course code
  2342. * @param int Learning path id
  2343. * @return int Total time
  2344. */
  2345. public static function get_last_connection_time_in_lp($student_id, $course_code, $lp_id, $session_id = 0)
  2346. {
  2347. $course = CourseManager :: get_course_information($course_code);
  2348. $student_id = intval($student_id);
  2349. $lp_id = intval($lp_id);
  2350. $last_time = 0;
  2351. $session_id = intval($session_id);
  2352. if (!empty($course)) {
  2353. $course_id = $course['real_id'];
  2354. $lp_table = Database :: get_course_table(TABLE_LP_MAIN);
  2355. $t_lpv = Database :: get_course_table(TABLE_LP_VIEW);
  2356. $t_lpiv = Database :: get_course_table(TABLE_LP_ITEM_VIEW);
  2357. // Check the real number of LPs corresponding to the filter in the
  2358. // database (and if no list was given, get them all)
  2359. $res_row_lp = Database::query("SELECT id FROM $lp_table WHERE c_id = $course_id AND id = $lp_id ");
  2360. $count_row_lp = Database::num_rows($res_row_lp);
  2361. // calculates last connection time
  2362. if ($count_row_lp > 0) {
  2363. $sql = 'SELECT MAX(start_time)
  2364. FROM ' . $t_lpiv . ' AS item_view
  2365. INNER JOIN ' . $t_lpv . ' AS view
  2366. ON item_view.lp_view_id = view.id
  2367. WHERE
  2368. item_view.c_id = '.$course_id.' AND
  2369. view.c_id = '.$course_id.' AND
  2370. view.lp_id = '.$lp_id.'
  2371. AND view.user_id = '.$student_id.'
  2372. AND view.session_id = '.$session_id;
  2373. $rs = Database::query($sql);
  2374. if (Database :: num_rows($rs) > 0) {
  2375. $last_time = Database :: result($rs, 0, 0);
  2376. }
  2377. }
  2378. }
  2379. return $last_time;
  2380. }
  2381. /**
  2382. * gets the list of students followed by coach
  2383. * @param int Coach id
  2384. * @return array List of students
  2385. */
  2386. public static function get_student_followed_by_coach($coach_id)
  2387. {
  2388. $coach_id = intval($coach_id);
  2389. $tbl_session_course_user = Database :: get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
  2390. $tbl_session_course = Database :: get_main_table(TABLE_MAIN_SESSION_COURSE);
  2391. $tbl_session_user = Database :: get_main_table(TABLE_MAIN_SESSION_USER);
  2392. $tbl_session = Database :: get_main_table(TABLE_MAIN_SESSION);
  2393. $a_students = array ();
  2394. // At first, courses where $coach_id is coach of the course //
  2395. $sql = 'SELECT id_session, course_code
  2396. FROM ' . $tbl_session_course_user . '
  2397. WHERE id_user=' . $coach_id.' AND status=2';
  2398. if (api_is_multiple_url_enabled()) {
  2399. $tbl_session_rel_access_url= Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_SESSION);
  2400. $access_url_id = api_get_current_access_url_id();
  2401. if ($access_url_id != -1) {
  2402. $sql = 'SELECT scu.id_session, scu.course_code
  2403. FROM ' . $tbl_session_course_user . ' scu
  2404. INNER JOIN '.$tbl_session_rel_access_url.' sru
  2405. ON (scu.id_session=sru.session_id)
  2406. WHERE
  2407. scu.id_user=' . $coach_id.' AND
  2408. scu.status=2 AND
  2409. sru.access_url_id = '.$access_url_id;
  2410. }
  2411. }
  2412. $result = Database::query($sql);
  2413. while ($a_courses = Database::fetch_array($result)) {
  2414. $course_code = $a_courses["course_code"];
  2415. $id_session = $a_courses["id_session"];
  2416. $sql = "SELECT distinct srcru.id_user
  2417. FROM $tbl_session_course_user AS srcru, $tbl_session_user sru
  2418. WHERE
  2419. srcru.id_user = sru.id_user AND
  2420. sru.relation_type<>".SESSION_RELATION_TYPE_RRHH." AND
  2421. srcru.id_session = sru.id_session AND
  2422. srcru.course_code='$course_code' AND
  2423. srcru.id_session='$id_session'";
  2424. $rs = Database::query($sql);
  2425. while ($row = Database::fetch_array($rs)) {
  2426. $a_students[$row['id_user']] = $row['id_user'];
  2427. }
  2428. }
  2429. // Then, courses where $coach_id is coach of the session //
  2430. $sql = 'SELECT session_course_user.id_user
  2431. FROM ' . $tbl_session_course_user . ' as session_course_user
  2432. INNER JOIN '.$tbl_session_user.' sru ON session_course_user.id_user = sru.id_user AND session_course_user.id_session = sru.id_session
  2433. INNER JOIN ' . $tbl_session_course . ' as session_course
  2434. ON session_course.course_code = session_course_user.course_code
  2435. AND session_course_user.id_session = session_course.id_session
  2436. INNER JOIN ' . $tbl_session . ' as session
  2437. ON session.id = session_course.id_session
  2438. AND session.id_coach = ' . $coach_id;
  2439. if (api_is_multiple_url_enabled()) {
  2440. $tbl_session_rel_access_url= Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_SESSION);
  2441. $access_url_id = api_get_current_access_url_id();
  2442. if ($access_url_id != -1){
  2443. $sql = 'SELECT session_course_user.id_user
  2444. FROM ' . $tbl_session_course_user . ' as session_course_user
  2445. INNER JOIN '.$tbl_session_user.' sru
  2446. ON session_course_user.id_user = sru.id_user AND
  2447. session_course_user.id_session = sru.id_session
  2448. INNER JOIN ' . $tbl_session_course . ' as session_course
  2449. ON session_course.course_code = session_course_user.course_code AND
  2450. session_course_user.id_session = session_course.id_session
  2451. INNER JOIN ' . $tbl_session . ' as session
  2452. ON session.id = session_course.id_session AND
  2453. session.id_coach = ' . $coach_id.'
  2454. INNER JOIN '.$tbl_session_rel_access_url.' session_rel_url
  2455. ON session.id = session_rel_url.session_id WHERE access_url_id = '.$access_url_id;
  2456. }
  2457. }
  2458. $result = Database::query($sql);
  2459. while ($row = Database::fetch_array($result)) {
  2460. $a_students[$row['id_user']] = $row['id_user'];
  2461. }
  2462. return $a_students;
  2463. }
  2464. /**
  2465. * Get student followed by a coach inside a session
  2466. * @param int Session id
  2467. * @param int Coach id
  2468. * @return array students list
  2469. */
  2470. public static function get_student_followed_by_coach_in_a_session($id_session, $coach_id)
  2471. {
  2472. $coach_id = intval($coach_id);
  2473. $tbl_session_course_user = Database :: get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
  2474. $tbl_session = Database :: get_main_table(TABLE_MAIN_SESSION);
  2475. $a_students = array ();
  2476. // At first, courses where $coach_id is coach of the course //
  2477. $sql = 'SELECT course_code FROM ' . $tbl_session_course_user . ' WHERE id_session="' . $id_session . '" AND id_user=' . $coach_id.' AND status=2';
  2478. $result = Database::query($sql);
  2479. while ($a_courses = Database::fetch_array($result)) {
  2480. $course_code = $a_courses["course_code"];
  2481. $sql = "SELECT distinct srcru.id_user
  2482. FROM $tbl_session_course_user AS srcru
  2483. WHERE
  2484. course_code='$course_code' AND
  2485. id_session = '" . $id_session . "'";
  2486. $rs = Database::query($sql);
  2487. while ($row = Database::fetch_array($rs)) {
  2488. $a_students[$row['id_user']] = $row['id_user'];
  2489. }
  2490. }
  2491. // Then, courses where $coach_id is coach of the session
  2492. $sql = 'SELECT id_coach FROM ' . $tbl_session . '
  2493. WHERE id="' . $id_session.'" AND id_coach="' . $coach_id . '"';
  2494. $result = Database::query($sql);
  2495. //He is the session_coach so we select all the users in the session
  2496. if (Database::num_rows($result) > 0) {
  2497. $sql = 'SELECT DISTINCT srcru.id_user
  2498. FROM ' . $tbl_session_course_user . ' AS srcru
  2499. WHERE id_session="' . $id_session . '"';
  2500. $result = Database::query($sql);
  2501. while ($row = Database::fetch_array($result)) {
  2502. $a_students[$row['id_user']] = $row['id_user'];
  2503. }
  2504. }
  2505. return $a_students;
  2506. }
  2507. /**
  2508. * Check if a coach is allowed to follow a student
  2509. * @param int Coach id
  2510. * @param int Student id
  2511. * @return bool
  2512. */
  2513. public static function is_allowed_to_coach_student($coach_id, $student_id)
  2514. {
  2515. $coach_id = intval($coach_id);
  2516. $student_id = intval($student_id);
  2517. $tbl_session_course_user = Database :: get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
  2518. $tbl_session_course = Database :: get_main_table(TABLE_MAIN_SESSION_COURSE);
  2519. $tbl_session = Database :: get_main_table(TABLE_MAIN_SESSION);
  2520. // At first, courses where $coach_id is coach of the course //
  2521. $sql = 'SELECT 1 FROM ' . $tbl_session_course_user . ' WHERE id_user=' . $coach_id .' AND status=2';
  2522. $result = Database::query($sql);
  2523. if (Database::num_rows($result) > 0) {
  2524. return true;
  2525. }
  2526. // Then, courses where $coach_id is coach of the session
  2527. $sql = 'SELECT session_course_user.id_user
  2528. FROM ' . $tbl_session_course_user . ' as session_course_user
  2529. INNER JOIN ' . $tbl_session_course . ' as session_course
  2530. ON session_course.course_code = session_course_user.course_code
  2531. INNER JOIN ' . $tbl_session . ' as session
  2532. ON session.id = session_course.id_session
  2533. AND session.id_coach = ' . $coach_id . '
  2534. WHERE id_user = ' . $student_id;
  2535. $result = Database::query($sql);
  2536. if (Database::num_rows($result) > 0) {
  2537. return true;
  2538. }
  2539. return false;
  2540. }
  2541. /**
  2542. * Get courses followed by coach
  2543. * @param int Coach id
  2544. * @param int Session id (optional)
  2545. * @return array Courses list
  2546. */
  2547. public static function get_courses_followed_by_coach($coach_id, $id_session = null)
  2548. {
  2549. $coach_id = intval($coach_id);
  2550. if (!empty($id_session)) {
  2551. $id_session = intval($id_session);
  2552. }
  2553. $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
  2554. $tbl_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
  2555. $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
  2556. $tbl_course = Database::get_main_table(TABLE_MAIN_COURSE);
  2557. // At first, courses where $coach_id is coach of the course.
  2558. $sql = 'SELECT DISTINCT course_code
  2559. FROM ' . $tbl_session_course_user . '
  2560. WHERE id_user = ' . $coach_id.' AND status = 2';
  2561. if (api_is_multiple_url_enabled()) {
  2562. $tbl_course_rel_access_url= Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
  2563. $access_url_id = api_get_current_access_url_id();
  2564. if ($access_url_id != -1){
  2565. $sql = 'SELECT DISTINCT scu.course_code
  2566. FROM ' . $tbl_session_course_user . ' scu
  2567. INNER JOIN '.$tbl_course_rel_access_url.' cru
  2568. ON (scu.course_code = cru.course_code)
  2569. WHERE
  2570. scu.id_user=' . $coach_id.' AND
  2571. scu.status=2 AND
  2572. cru.access_url_id = '.$access_url_id;
  2573. }
  2574. }
  2575. if (!empty($id_session)) {
  2576. $sql .= ' AND id_session=' . $id_session;
  2577. }
  2578. $courseList = array();
  2579. $result = Database::query($sql);
  2580. while ($row = Database::fetch_array($result)) {
  2581. $courseList[$row['course_code']] = $row['course_code'];
  2582. }
  2583. // Then, courses where $coach_id is coach of the session
  2584. $sql = 'SELECT DISTINCT session_course.course_code
  2585. FROM ' . $tbl_session_course . ' as session_course
  2586. INNER JOIN ' . $tbl_session . ' as session
  2587. ON session.id = session_course.id_session
  2588. AND session.id_coach = ' . $coach_id . '
  2589. INNER JOIN ' . $tbl_course . ' as course
  2590. ON course.code = session_course.course_code';
  2591. if (api_is_multiple_url_enabled()) {
  2592. $tbl_course_rel_access_url= Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
  2593. $access_url_id = api_get_current_access_url_id();
  2594. if ($access_url_id != -1){
  2595. $sql = 'SELECT DISTINCT session_course.course_code
  2596. FROM ' . $tbl_session_course . ' as session_course
  2597. INNER JOIN ' . $tbl_session . ' as session
  2598. ON session.id = session_course.id_session
  2599. AND session.id_coach = ' . $coach_id . '
  2600. INNER JOIN ' . $tbl_course . ' as course
  2601. ON course.code = session_course.course_code
  2602. INNER JOIN '.$tbl_course_rel_access_url.' course_rel_url
  2603. ON (session_course.course_code = course_rel_url.course_code)';
  2604. }
  2605. }
  2606. if (!empty ($id_session)) {
  2607. $sql .= ' WHERE session_course.id_session=' . $id_session;
  2608. if (api_is_multiple_url_enabled())
  2609. $sql .= ' AND access_url_id = '.$access_url_id;
  2610. } else {
  2611. if (api_is_multiple_url_enabled())
  2612. $sql .= ' WHERE access_url_id = '.$access_url_id;
  2613. }
  2614. $result = Database::query($sql);
  2615. while ($row = Database::fetch_array($result)) {
  2616. $courseList[$row['course_code']] = $row['course_code'];
  2617. }
  2618. return $courseList;
  2619. }
  2620. /**
  2621. * Get sessions coached by user
  2622. * @param $coach_id
  2623. * @param int $start
  2624. * @param int $limit
  2625. * @param bool $getCount
  2626. * @param null $keyword
  2627. * @return mixed
  2628. */
  2629. public static function get_sessions_coached_by_user(
  2630. $coach_id,
  2631. $start = 0,
  2632. $limit = 0,
  2633. $getCount = false,
  2634. $keyword = null
  2635. ) {
  2636. // table definition
  2637. $tbl_session = Database :: get_main_table(TABLE_MAIN_SESSION);
  2638. $tbl_session_course_user = Database :: get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
  2639. $coach_id = intval($coach_id);
  2640. $select = " SELECT * FROM ";
  2641. if ($getCount) {
  2642. $select = " SELECT count(DISTINCT id) as count FROM ";
  2643. }
  2644. $limitCondition = null;
  2645. if (!empty($start) && !empty($limit)) {
  2646. $limitCondition = " LIMIT ".intval($start).", ".intval($limit);
  2647. }
  2648. $keywordCondition = null;
  2649. if (!empty($keyword)) {
  2650. $keyword = Database::escape_string($keyword);
  2651. $keywordCondition = " AND (name LIKE '%$keyword%' ) ";
  2652. }
  2653. $tbl_session_rel_access_url= Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_SESSION);
  2654. $access_url_id = api_get_current_access_url_id();
  2655. $sql = "
  2656. $select
  2657. (
  2658. SELECT DISTINCT id, name, date_start, date_end
  2659. FROM $tbl_session session INNER JOIN $tbl_session_rel_access_url session_rel_url
  2660. ON (session.id = session_rel_url.session_id)
  2661. WHERE id_coach = $coach_id AND access_url_id = $access_url_id $keywordCondition
  2662. UNION
  2663. SELECT DISTINCT session.id, session.name, session.date_start, session.date_end
  2664. FROM $tbl_session as session
  2665. INNER JOIN $tbl_session_course_user as session_course_user
  2666. ON session.id = session_course_user.id_session AND
  2667. session_course_user.id_user= $coach_id AND
  2668. session_course_user.status=2
  2669. INNER JOIN $tbl_session_rel_access_url session_rel_url
  2670. ON (session.id = session_rel_url.session_id)
  2671. WHERE access_url_id = $access_url_id $keywordCondition
  2672. ) as sessions $limitCondition
  2673. ";
  2674. $rs = Database::query($sql);
  2675. if ($getCount) {
  2676. $row = Database::fetch_array($rs);
  2677. return $row['count'];
  2678. }
  2679. while ($row = Database::fetch_array($rs)) {
  2680. $a_sessions[$row["id"]] = $row;
  2681. }
  2682. if (is_array($a_sessions)) {
  2683. foreach ($a_sessions as & $session) {
  2684. if ($session['date_start'] == '0000-00-00') {
  2685. $session['status'] = get_lang('SessionActive');
  2686. }
  2687. else {
  2688. $date_start = explode('-', $session['date_start']);
  2689. $time_start = mktime(0, 0, 0, $date_start[1], $date_start[2], $date_start[0]);
  2690. $date_end = explode('-', $session['date_end']);
  2691. $time_end = mktime(0, 0, 0, $date_end[1], $date_end[2], $date_end[0]);
  2692. if ($time_start < time() && time() < $time_end) {
  2693. $session['status'] = get_lang('SessionActive');
  2694. } else {
  2695. if (time() < $time_start) {
  2696. $session['status'] = get_lang('SessionFuture');
  2697. } else {
  2698. if (time() > $time_end) {
  2699. $session['status'] = get_lang('SessionPast');
  2700. }
  2701. }
  2702. }
  2703. }
  2704. }
  2705. }
  2706. return $a_sessions;
  2707. }
  2708. /**
  2709. * Get courses list from a session
  2710. * @param int Session id
  2711. * @return array Courses list
  2712. */
  2713. public static function get_courses_list_from_session($session_id)
  2714. {
  2715. $session_id = intval($session_id);
  2716. // table definition
  2717. $tbl_session_course = Database :: get_main_table(TABLE_MAIN_SESSION_COURSE);
  2718. $sql = 'SELECT DISTINCT course_code
  2719. FROM ' . $tbl_session_course . '
  2720. WHERE id_session=' . $session_id;
  2721. $rs = Database::query($sql);
  2722. $a_courses = array ();
  2723. while ($row = Database::fetch_array($rs)) {
  2724. $a_courses[$row['course_code']] = $row;
  2725. }
  2726. return $a_courses;
  2727. }
  2728. /**
  2729. * Count the number of documents that an user has uploaded to a course
  2730. * @param int|array Student id(s)
  2731. * @param string Course code
  2732. * @param int Session id (optional), if param $session_id is null(default) return count of assignments including sessions, 0 = session is not filtered
  2733. * @return int Number of documents
  2734. */
  2735. public static function count_student_uploaded_documents($student_id, $course_code, $session_id = null)
  2736. {
  2737. // get the information of the course
  2738. $a_course = CourseManager::get_course_information($course_code);
  2739. if (!empty($a_course)) {
  2740. // table definition
  2741. $tbl_item_property = Database :: get_course_table(TABLE_ITEM_PROPERTY);
  2742. $tbl_document = Database :: get_course_table(TABLE_DOCUMENT);
  2743. $course_id = $a_course['real_id'];
  2744. if (is_array($student_id)) {
  2745. $studentList = array_map('intval', $student_id);
  2746. $condition_user = " AND ip.insert_user_id IN ('".implode(',', $studentList)."') ";
  2747. } else {
  2748. $student_id = intval($student_id);
  2749. $condition_user = " AND ip.insert_user_id = '$student_id' ";
  2750. }
  2751. $condition_session = null;
  2752. if (isset($session_id)) {
  2753. $session_id = intval($session_id);
  2754. $condition_session = " AND pub.session_id = $session_id ";
  2755. }
  2756. $sql = "SELECT count(ip.tool) AS count
  2757. FROM $tbl_item_property ip INNER JOIN $tbl_document pub
  2758. ON ip.ref = pub.id
  2759. WHERE ip.c_id = $course_id AND
  2760. pub.c_id = $course_id AND
  2761. pub.filetype ='file' AND
  2762. ip.tool = 'document'
  2763. $condition_user $condition_session ";
  2764. $rs = Database::query($sql);
  2765. $row = Database::fetch_row($rs);
  2766. return $row['count'];
  2767. }
  2768. return null;
  2769. }
  2770. /**
  2771. * Count assignments per student
  2772. * @param int|array Student id(s)
  2773. * @param string Course code
  2774. * @param int Session id (optional), if param $session_id is null(default) return count of assignments including sessions, 0 = session is not filtered
  2775. * @return int Count of assignments
  2776. */
  2777. public static function count_student_assignments($student_id, $course_code = null, $session_id = null)
  2778. {
  2779. if (empty($student_id)) {
  2780. return 0;
  2781. }
  2782. $conditions = array();
  2783. // Get the information of the course
  2784. $a_course = CourseManager::get_course_information($course_code);
  2785. if (!empty($a_course)) {
  2786. $course_id = $a_course['real_id'];
  2787. $conditions[]= " ip.c_id = $course_id AND pub.c_id = $course_id ";
  2788. }
  2789. // table definition
  2790. $tbl_item_property = Database :: get_course_table(TABLE_ITEM_PROPERTY);
  2791. $tbl_student_publication = Database :: get_course_table(TABLE_STUDENT_PUBLICATION);
  2792. if (is_array($student_id)) {
  2793. $studentList = array_map('intval', $student_id);
  2794. $conditions[]= " ip.insert_user_id IN ('".implode("','", $studentList)."') ";
  2795. } else {
  2796. $student_id = intval($student_id);
  2797. $conditions[]= " ip.insert_user_id = '$student_id' ";
  2798. }
  2799. if (isset($session_id)) {
  2800. $session_id = intval($session_id);
  2801. $conditions[]= " pub.session_id = $session_id ";
  2802. }
  2803. $conditionToString = implode('AND', $conditions);
  2804. $sql = "SELECT count(ip.tool) as count
  2805. FROM $tbl_item_property ip
  2806. INNER JOIN $tbl_student_publication pub ON ip.ref = pub.id
  2807. WHERE
  2808. ip.tool='work' AND
  2809. $conditionToString";
  2810. $rs = Database::query($sql);
  2811. $row = Database::fetch_array($rs, 'ASSOC');
  2812. return $row['count'];
  2813. }
  2814. /**
  2815. * Count messages per student inside forum tool
  2816. * @param int|array Student id
  2817. * @param string Course code
  2818. * @param int Session id (optional), if param $session_id is
  2819. * null(default) return count of messages including sessions, 0 = session is not filtered
  2820. * @return int Count of messages
  2821. */
  2822. public static function count_student_messages($student_id, $courseCode = null, $session_id = null)
  2823. {
  2824. if (empty($student_id)) {
  2825. return 0;
  2826. }
  2827. $courseInfo = api_get_course_info($courseCode);
  2828. $courseCondition = null;
  2829. $conditions = array();
  2830. if (!empty($courseInfo)) {
  2831. $course_id = $courseInfo['real_id'];
  2832. $conditions[]= " post.c_id = $course_id AND forum.c_id = $course_id ";
  2833. }
  2834. // Table definition.
  2835. $tbl_forum_post = Database :: get_course_table(TABLE_FORUM_POST);
  2836. $tbl_forum = Database :: get_course_table(TABLE_FORUM);
  2837. if (is_array($student_id)) {
  2838. $studentList = array_map('intval', $student_id);
  2839. $conditions[]= " post.poster_id IN ('".implode("','", $studentList)."') ";
  2840. } else {
  2841. $student_id = intval($student_id);
  2842. $conditions[]= " post.poster_id = '$student_id' ";
  2843. }
  2844. if (isset($session_id)) {
  2845. $session_id = intval($session_id);
  2846. $conditions[]= " forum.session_id = $session_id";
  2847. }
  2848. $conditionsToString = implode('AND ', $conditions);
  2849. $sql = "SELECT count(poster_id) as count
  2850. FROM $tbl_forum_post post INNER JOIN $tbl_forum forum
  2851. ON forum.forum_id = post.forum_id
  2852. WHERE $conditionsToString";
  2853. $rs = Database::query($sql);
  2854. $row = Database::fetch_array($rs, 'ASSOC');
  2855. $count = $row['count'];
  2856. return $count;
  2857. }
  2858. /**
  2859. * This function counts the number of post by course
  2860. * @param string Course code
  2861. * @param int Session id (optional), if param $session_id is null(default) it'll return results including sessions, 0 = session is not filtered
  2862. * @return int The number of post by course
  2863. */
  2864. public static function count_number_of_posts_by_course($course_code, $session_id = null)
  2865. {
  2866. $a_course = CourseManager :: get_course_information($course_code);
  2867. if (!empty($a_course)) {
  2868. $tbl_posts = Database :: get_course_table(TABLE_FORUM_POST);
  2869. $tbl_forums = Database :: get_course_table(TABLE_FORUM);
  2870. $condition_session = '';
  2871. if (isset($session_id)) {
  2872. $session_id = intval($session_id);
  2873. $condition_session = ' AND f.session_id = '. $session_id;
  2874. }
  2875. $course_id = $a_course['real_id'];
  2876. $sql = "SELECT count(*) FROM $tbl_posts p INNER JOIN $tbl_forums f
  2877. ON f.forum_id = p.forum_id
  2878. WHERE p.c_id = $course_id AND
  2879. f.c_id = $course_id
  2880. $condition_session
  2881. ";
  2882. $result = Database::query($sql);
  2883. $row = Database::fetch_row($result);
  2884. $count = $row[0];
  2885. return $count;
  2886. } else {
  2887. return null;
  2888. }
  2889. }
  2890. /**
  2891. * This function counts the number of threads by course
  2892. * @param string Course code
  2893. * @param int Session id (optional), if param $session_id is null(default) it'll return results including sessions, 0 = session is not filtered
  2894. * @return int The number of threads by course
  2895. */
  2896. public static function count_number_of_threads_by_course($course_code, $session_id = null)
  2897. {
  2898. $course_info = api_get_course_info($course_code);
  2899. if (empty($course_info)) {
  2900. return null;
  2901. }
  2902. $course_id = $course_info['real_id'];
  2903. $tbl_threads = Database :: get_course_table(TABLE_FORUM_THREAD);
  2904. $tbl_forums = Database :: get_course_table(TABLE_FORUM);
  2905. $condition_session = '';
  2906. if (isset($session_id)) {
  2907. $session_id = intval($session_id);
  2908. $condition_session = ' AND f.session_id = '. $session_id;
  2909. }
  2910. $sql = "SELECT count(*) FROM $tbl_threads t INNER JOIN $tbl_forums f ON f.forum_id = t.forum_id
  2911. WHERE t.c_id = $course_id AND f.c_id = $course_id $condition_session ";
  2912. $result = Database::query($sql);
  2913. if (Database::num_rows($result)) {
  2914. $row = Database::fetch_row($result);
  2915. $count = $row[0];
  2916. return $count;
  2917. } else {
  2918. return null;
  2919. }
  2920. }
  2921. /**
  2922. * This function counts the number of forums by course
  2923. * @param string Course code
  2924. * @param int Session id (optional), if param $session_id is null(default) it'll return results including sessions, 0 = session is not filtered
  2925. * @return int The number of forums by course
  2926. */
  2927. public static function count_number_of_forums_by_course($course_code, $session_id = null)
  2928. {
  2929. $course_info = api_get_course_info($course_code);
  2930. if (empty($course_info)) {
  2931. return null;
  2932. }
  2933. $course_id = $course_info['real_id'];
  2934. $condition_session = '';
  2935. if (isset($session_id)) {
  2936. $session_id = intval($session_id);
  2937. $condition_session = ' session_id = '. $session_id;
  2938. }
  2939. $tbl_forums = Database :: get_course_table(TABLE_FORUM);
  2940. $sql = "SELECT count(*) FROM $tbl_forums WHERE c_id = $course_id AND $condition_session";
  2941. $result = Database::query($sql);
  2942. if (Database::num_rows($result)) {
  2943. $row = Database::fetch_row($result);
  2944. $count = $row[0];
  2945. return $count;
  2946. } else {
  2947. return null;
  2948. }
  2949. }
  2950. /**
  2951. * This function counts the chat last connections by course in x days
  2952. * @param string Course code
  2953. * @param int Last x days
  2954. * @param int Session id (optional)
  2955. * @return int Chat last connections by course in x days
  2956. */
  2957. public static function chat_connections_during_last_x_days_by_course($course_code, $last_days, $session_id = 0)
  2958. {
  2959. $course_info = api_get_course_info($course_code);
  2960. if (empty($course_info)) {
  2961. return null;
  2962. }
  2963. $course_id = $course_info['real_id'];
  2964. //protect data
  2965. $last_days = intval($last_days);
  2966. $course_code = Database::escape_string($course_code);
  2967. $session_id = intval($session_id);
  2968. $tbl_stats_access = Database :: get_statistic_table(TABLE_STATISTIC_TRACK_E_ACCESS);
  2969. $sql = "SELECT count(*) FROM $tbl_stats_access WHERE DATE_SUB(NOW(),INTERVAL $last_days DAY) <= access_date
  2970. AND access_cours_code = '$course_code' AND access_tool='".TOOL_CHAT."' AND access_session_id='$session_id' ";
  2971. $result = Database::query($sql);
  2972. if (Database::num_rows($result)) {
  2973. $row = Database::fetch_row($result);
  2974. $count = $row[0];
  2975. return $count;
  2976. } else {
  2977. return null;
  2978. }
  2979. }
  2980. /**
  2981. * This function gets the last student's connection in chat
  2982. * @param int Student id
  2983. * @param string Course code
  2984. * @param int Session id (optional)
  2985. * @return string datetime formatted without day (e.g: February 23, 2010 10:20:50 )
  2986. */
  2987. public static function chat_last_connection($student_id, $course_code, $session_id = 0)
  2988. {
  2989. $student_id = intval($student_id);
  2990. $course_code= Database::escape_string($course_code);
  2991. $session_id = intval($session_id);
  2992. $date_time = '';
  2993. // table definition
  2994. $tbl_stats_access = Database :: get_statistic_table(TABLE_STATISTIC_TRACK_E_LASTACCESS);
  2995. $sql = "SELECT access_date
  2996. FROM $tbl_stats_access
  2997. WHERE
  2998. access_tool='".TOOL_CHAT."' AND
  2999. access_user_id='$student_id' AND
  3000. access_cours_code = '$course_code' AND
  3001. access_session_id = '$session_id'
  3002. ORDER BY access_date DESC limit 1";
  3003. $rs = Database::query($sql);
  3004. if (Database::num_rows($rs) > 0) {
  3005. $row = Database::fetch_array($rs);
  3006. $date_time = api_convert_and_format_date($row['access_date'], null, date_default_timezone_get());
  3007. }
  3008. return $date_time;
  3009. }
  3010. /**
  3011. * Get count student's visited links
  3012. * @param int Student id
  3013. * @param string Course code
  3014. * @param int Session id (optional)
  3015. * @return int count of visited links
  3016. */
  3017. public static function count_student_visited_links($student_id, $course_code, $session_id = 0)
  3018. {
  3019. // protect datas
  3020. $student_id = intval($student_id);
  3021. $course_code = Database::escape_string($course_code);
  3022. $session_id = intval($session_id);
  3023. // table definition
  3024. $tbl_stats_links = Database::get_statistic_table(TABLE_STATISTIC_TRACK_E_LINKS);
  3025. $sql = 'SELECT 1
  3026. FROM '.$tbl_stats_links.'
  3027. WHERE
  3028. links_user_id= '.$student_id.' AND
  3029. links_cours_id = "'.$course_code.'" AND
  3030. links_session_id = '.$session_id.' ';
  3031. $rs = Database::query($sql);
  3032. return Database::num_rows($rs);
  3033. }
  3034. /**
  3035. * Get count student downloaded documents
  3036. * @param int Student id
  3037. * @param string Course code
  3038. * @param int Session id (optional)
  3039. * @return int Count downloaded documents
  3040. */
  3041. public static function count_student_downloaded_documents($student_id, $course_code, $session_id = 0)
  3042. {
  3043. // protect datas
  3044. $student_id = intval($student_id);
  3045. $course_code = Database::escape_string($course_code);
  3046. $session_id = intval($session_id);
  3047. // table definition
  3048. $tbl_stats_documents = Database::get_statistic_table(TABLE_STATISTIC_TRACK_E_DOWNLOADS);
  3049. $sql = 'SELECT 1
  3050. FROM ' . $tbl_stats_documents . '
  3051. WHERE down_user_id = '.$student_id.'
  3052. AND down_cours_id = "'.$course_code.'"
  3053. AND down_session_id = '.$session_id.' ';
  3054. $rs = Database::query($sql);
  3055. return Database::num_rows($rs);
  3056. }
  3057. /**
  3058. * Get course list inside a session from a student
  3059. * @param int Student id
  3060. * @param int Session id (optional)
  3061. * @return array Courses list
  3062. */
  3063. public static function get_course_list_in_session_from_student($user_id, $id_session = 0)
  3064. {
  3065. $user_id = intval($user_id);
  3066. $id_session = intval($id_session);
  3067. $tbl_session_course_user = Database :: get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
  3068. $sql = 'SELECT course_code
  3069. FROM ' . $tbl_session_course_user . '
  3070. WHERE
  3071. id_user="' . $user_id . '" AND
  3072. id_session="' . $id_session . '"';
  3073. $result = Database::query($sql);
  3074. $a_courses = array ();
  3075. while ($row = Database::fetch_array($result)) {
  3076. $a_courses[$row['course_code']] = $row['course_code'];
  3077. }
  3078. return $a_courses;
  3079. }
  3080. /**
  3081. * Get inactives students in course
  3082. * @param string Course code
  3083. * @param string Since login course date (optional, default = 'never')
  3084. * @param int Session id (optional)
  3085. * @return array Inactives users
  3086. */
  3087. public static function get_inactives_students_in_course($course_code, $since = 'never', $session_id=0)
  3088. {
  3089. $tbl_track_login = Database :: get_statistic_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
  3090. $tbl_session_course_user = Database :: get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
  3091. $table_course_rel_user = Database :: get_main_table(TABLE_MAIN_COURSE_USER);
  3092. $inner = '';
  3093. if ($session_id!=0) {
  3094. $inner = ' INNER JOIN '.$tbl_session_course_user.' session_course_user
  3095. ON stats_login.course_code = session_course_user.course_code
  3096. AND session_course_user.id_session = '.intval($session_id).'
  3097. AND session_course_user.id_user = stats_login.user_id ';
  3098. }
  3099. $sql = 'SELECT user_id, MAX(login_course_date) max_date FROM'.$tbl_track_login.' stats_login'.$inner.'
  3100. GROUP BY user_id
  3101. HAVING DATE_SUB( NOW(), INTERVAL '.$since.' DAY) > max_date ';
  3102. //HAVING DATE_ADD(max_date, INTERVAL '.$since.' DAY) < NOW() ';
  3103. if ($since == 'never') {
  3104. $sql = 'SELECT course_user.user_id FROM '.$table_course_rel_user.' course_user
  3105. LEFT JOIN '. $tbl_track_login.' stats_login
  3106. ON course_user.user_id = stats_login.user_id AND relation_type<>'.COURSE_RELATION_TYPE_RRHH.' '.
  3107. $inner.'
  3108. WHERE course_user.course_code = \''.Database::escape_string($course_code).'\'
  3109. AND stats_login.login_course_date IS NULL
  3110. GROUP BY course_user.user_id';
  3111. }
  3112. $rs = Database::query($sql);
  3113. $inactive_users = array();
  3114. while($user = Database::fetch_array($rs)) {
  3115. $inactive_users[] = $user['user_id'];
  3116. }
  3117. return $inactive_users;
  3118. }
  3119. /**
  3120. * Get count login per student
  3121. * @param int Student id
  3122. * @param string Course code
  3123. * @param int Session id (optional)
  3124. * @return int count login
  3125. */
  3126. public static function count_login_per_student($student_id, $course_code, $session_id = 0)
  3127. {
  3128. $student_id = intval($student_id);
  3129. $course_code = Database::escape_string($course_code);
  3130. $session_id = intval($session_id);
  3131. $tbl_course_rel_user = Database::get_statistic_table(TABLE_STATISTIC_TRACK_E_ACCESS);
  3132. $sql = 'SELECT '.$student_id.'
  3133. FROM ' . $tbl_course_rel_user . '
  3134. WHERE access_user_id=' . $student_id . '
  3135. AND access_cours_code="' . $course_code . '" AND access_session_id = "'.$session_id.'" ';
  3136. $rs = Database::query($sql);
  3137. $nb_login = Database::num_rows($rs);
  3138. return $nb_login;
  3139. }
  3140. /**
  3141. * Get students followed by a human resources manager
  3142. * @param int Drh id
  3143. * @return array Student list
  3144. */
  3145. public static function get_student_followed_by_drh($hr_dept_id)
  3146. {
  3147. $hr_dept_id = intval($hr_dept_id);
  3148. $a_students = array();
  3149. $tbl_user = Database :: get_main_table(TABLE_MAIN_USER);
  3150. $sql = 'SELECT DISTINCT user_id FROM '.$tbl_user.' as user
  3151. WHERE hr_dept_id='.$hr_dept_id;
  3152. $rs = Database::query($sql);
  3153. while($user = Database :: fetch_array($rs)) {
  3154. $a_students[$user['user_id']] = $user['user_id'];
  3155. }
  3156. return $a_students;
  3157. }
  3158. /**
  3159. * Gets the average of test and scorm inside a learning path
  3160. * @param int User id
  3161. * @param string Course id
  3162. * @return float average of test
  3163. * @author isaac flores paz
  3164. * @deprecated get_avg_student_score should be use
  3165. */
  3166. public static function get_average_test_scorm_and_lp($user_id, $course_id)
  3167. {
  3168. //the score inside the Reporting table
  3169. $course_info = api_get_course_info($course_id);
  3170. $course_id = $course_info['real_id'];
  3171. $lp_table = Database :: get_course_table(TABLE_LP_MAIN);
  3172. $lp_view_table = Database :: get_course_table(TABLE_LP_VIEW);
  3173. $lp_item_view_table = Database :: get_course_table(TABLE_LP_ITEM_VIEW);
  3174. $lp_item_table = Database :: get_course_table(TABLE_LP_ITEM);
  3175. $sql_type = "SELECT id, lp_type FROM $lp_table WHERE c_id = $course_id";
  3176. $rs_type=Database::query($sql_type);
  3177. $average_data=0;
  3178. $count_loop=0;
  3179. $average_data_sum = 0;
  3180. $lp_list = array();
  3181. while ($row_type = Database::fetch_array($rs_type)) {
  3182. $lp_list[] = $row_type['id'];
  3183. if ($row_type['lp_type']==1) {
  3184. //lp chamilo
  3185. $sql = "SELECT id FROM $lp_view_table WHERE c_id = $course_id AND user_id = '".intval($user_id)."' and lp_id='".$row_type['id']."'";
  3186. $rs_last_lp_view_id = Database::query($sql);
  3187. $lp_view_id = intval(Database::result($rs_last_lp_view_id,0,'id'));
  3188. $sql_list_view="SELECT li.max_score,lv.user_id,liw.score,(liw.score/li.max_score) as sum_data
  3189. FROM $lp_item_table li
  3190. INNER JOIN $lp_view_table lv
  3191. ON li.lp_id=lv.lp_id
  3192. INNER JOIN $lp_item_view_table liw
  3193. ON liw.lp_item_id=li.id
  3194. WHERE li.c_id = $course_id AND
  3195. liw.c_id = $course_id AND
  3196. lv.c_id = $course_id AND
  3197. lv.user_id= $user_id AND
  3198. li.item_type = 'quiz' AND
  3199. liw.lp_view_id= $lp_view_id";
  3200. $sum=0;
  3201. $tot=0;
  3202. $rs_list_view1=Database::query($sql_list_view);
  3203. while ($row_list_view=Database::fetch_array($rs_list_view1)) {
  3204. $sum=$sum+$row_list_view['sum_data'];
  3205. $tot++;
  3206. }
  3207. if ($tot==0) {
  3208. $tot=1;
  3209. }
  3210. $average_data1=$sum/$tot;
  3211. } elseif ($row_type['lp_type']==2) {
  3212. //lp scorm
  3213. $sql = "SELECT id FROM $lp_view_table
  3214. WHERE c_id = $course_id AND user_id = '".intval($user_id)."' and lp_id='".$row_type['id']."'";
  3215. $rs_last_lp_view_id = Database::query($sql);
  3216. $lp_view_id = intval(Database::result($rs_last_lp_view_id,0,'id'));
  3217. $sql_list_view = "SELECT li.max_score,lv.user_id,liw.score,((liw.score/li.max_score)*100) as sum_data
  3218. FROM $lp_item_table li
  3219. INNER JOIN $lp_view_table lv
  3220. ON li.lp_id=lv.lp_id
  3221. INNER JOIN $lp_item_view_table liw ON liw.lp_item_id=li.id
  3222. WHERE li.c_id = $course_id AND
  3223. liw.c_id = $course_id AND
  3224. lv.c_id = $course_id AND
  3225. lv.user_id= $user_id AND
  3226. (li.item_type = 'sco' OR li.item_type='quiz') AND
  3227. liw.lp_view_id = $lp_view_id";
  3228. $tot=0;
  3229. $sum=0;
  3230. $rs_list_view2=Database::query($sql_list_view);
  3231. while ($row_list_view=Database::fetch_array($rs_list_view2)) {
  3232. $sum=$sum+$row_list_view['sum_data'];
  3233. $tot++;
  3234. }
  3235. if ($tot==0) {
  3236. $tot=1;
  3237. }
  3238. $average_data2=$sum/$tot;
  3239. }
  3240. $average_data_sum = $average_data_sum+$average_data1+$average_data2;
  3241. $average_data2=0;
  3242. $average_data1=0;
  3243. $count_loop++;
  3244. }
  3245. //We only count the LP that have an exercise to get the average
  3246. $lp_with_quiz = 0;
  3247. foreach ($lp_list as $lp_id) {
  3248. //check if LP have a score
  3249. $sql = "SELECT count(id) as count FROM $lp_item_table
  3250. WHERE c_id = $course_id AND item_type = 'quiz' AND lp_id = ".$lp_id." ";
  3251. $result_have_quiz = Database::query($sql);
  3252. if (Database::num_rows($result_have_quiz) > 0 ) {
  3253. $row = Database::fetch_array($result_have_quiz,'ASSOC');
  3254. if (is_numeric($row['count']) && $row['count'] != 0) {
  3255. $lp_with_quiz++;
  3256. }
  3257. }
  3258. }
  3259. if ($lp_with_quiz > 0) {
  3260. $avg_student_score = round(($average_data_sum / $lp_with_quiz * 100), 2);
  3261. }
  3262. return $avg_student_score;
  3263. }
  3264. /**
  3265. * get count clicks about tools most used by course
  3266. * @param string Course code
  3267. * @param int Session id (optional), if param $session_id is null(default) it'll return results including sessions, 0 = session is not filtered
  3268. * @return array tools data
  3269. */
  3270. public static function get_tools_most_used_by_course($course_code, $session_id = null)
  3271. {
  3272. //protect data
  3273. $course_code = Database::escape_string($course_code);
  3274. $data = array();
  3275. $TABLETRACK_ACCESS = Database::get_statistic_table(TABLE_STATISTIC_TRACK_E_LASTACCESS);
  3276. $condition_session = '';
  3277. if (isset($session_id)) {
  3278. $session_id = intval($session_id);
  3279. $condition_session = ' AND access_session_id = '. $session_id;
  3280. }
  3281. $sql = "SELECT access_tool, COUNT(DISTINCT access_user_id),count( access_tool ) as count_access_tool
  3282. FROM $TABLETRACK_ACCESS
  3283. WHERE
  3284. access_tool IS NOT NULL AND
  3285. access_tool != '' AND
  3286. access_cours_code = '$course_code'
  3287. $condition_session
  3288. GROUP BY access_tool
  3289. ORDER BY count_access_tool DESC
  3290. LIMIT 0, 3";
  3291. $rs = Database::query($sql);
  3292. if (Database::num_rows($rs) > 0) {
  3293. while ($row = Database::fetch_array($rs)) {
  3294. $data[] = $row;
  3295. }
  3296. }
  3297. return $data;
  3298. }
  3299. /**
  3300. * Get total clicks
  3301. * THIS FUNCTION IS NOT BEEN USED, IT WAS MEANT TO BE USE WITH track_e_course_access.date_from and track_e_course_access.date_to,
  3302. * BUT NO ROW MATCH THE CONDITION, IT SHOULD BE FINE TO USE IT WHEN YOU USE USER DEFINED DATES AND NO CHAMILO DATES
  3303. * @param int User Id
  3304. * @param int Course Id
  3305. * @param int Session Id (optional), if param $session_id is null(default) it'll return results including sessions, 0 = session is not filtered
  3306. * @param string Date from
  3307. * @param string Date to
  3308. * @return array Data
  3309. * @author César Perales cesar.perales@beeznest.com 2014-01-16
  3310. */
  3311. public static function get_total_clicks($userId, $courseId, $sessionId = 0, $date_from = '', $date_to = '')
  3312. {
  3313. $course = api_get_course_info_by_id($courseId);
  3314. $tables = array(
  3315. TABLE_STATISTIC_TRACK_E_LASTACCESS => array(
  3316. 'course' => 'access_cours_code',
  3317. 'session' => 'access_session_id',
  3318. 'user' => 'access_user_id',
  3319. 'start_date'=> 'access_date',
  3320. ),
  3321. TABLE_STATISTIC_TRACK_E_ACCESS => array(
  3322. 'course' => 'access_cours_code',
  3323. 'session' => 'access_session_id',
  3324. 'user' => 'access_user_id',
  3325. 'start_date'=> 'access_date',
  3326. ),
  3327. #TABLE_STATISTIC_TRACK_E_LOGIN, array(,, 'login_date', 'logout_date');
  3328. TABLE_STATISTIC_TRACK_E_DOWNLOADS => array(
  3329. 'course' => 'down_cours_id',
  3330. 'session' => 'down_session_id',
  3331. 'user' => 'down_user_id',
  3332. 'start_date'=> 'down_date',
  3333. ),
  3334. TABLE_STATISTIC_TRACK_E_LINKS => array(
  3335. 'course' => 'links_cours_id',
  3336. 'session' => 'links_session_id',
  3337. 'user' => 'links_user_id',
  3338. 'start_date'=> 'links_date',
  3339. ),
  3340. TABLE_STATISTIC_TRACK_E_ONLINE => array(
  3341. 'course' => 'course',
  3342. 'session' => 'session_id',
  3343. 'user' => 'login_user_id',
  3344. 'start_date'=> 'login_date',
  3345. ),
  3346. #TABLE_STATISTIC_TRACK_E_HOTPOTATOES,
  3347. /*TABLE_STATISTIC_TRACK_E_COURSE_ACCESS => array(
  3348. 'course' => 'course_code',
  3349. 'session' => 'session_id',
  3350. 'user' => 'user_id',
  3351. 'start_date'=> 'login_course_date',
  3352. 'end_date' => 'logout_course_date',
  3353. ),*/
  3354. TABLE_STATISTIC_TRACK_E_EXERCICES => array(
  3355. 'course' => 'exe_cours_id',
  3356. 'session' => 'session_id',
  3357. 'user' => 'exe_user_id',
  3358. 'start_date'=> 'exe_date',
  3359. ),
  3360. TABLE_STATISTIC_TRACK_E_ATTEMPT => array(
  3361. 'course' => 'course_code',
  3362. 'session' => 'session_id',
  3363. 'user' => 'user_id',
  3364. 'start_date'=> 'tms',
  3365. ),
  3366. #TABLE_STATISTIC_TRACK_E_ATTEMPT_RECORDING,
  3367. #TABLE_STATISTIC_TRACK_E_DEFAULT,
  3368. TABLE_STATISTIC_TRACK_E_UPLOADS => array(
  3369. 'course' => 'upload_cours_id',
  3370. 'session' => 'upload_session_id',
  3371. 'user' => 'upload_user_id',
  3372. 'start_date'=> 'upload_date',
  3373. ),
  3374. #TABLE_STATISTIC_TRACK_E_HOTSPOT,
  3375. #TABLE_STATISTIC_TRACK_E_ITEM_PROPERTY,
  3376. #TABLE_STATISTIC_TRACK_E_OPEN,
  3377. );
  3378. $error_sql = '';
  3379. foreach ($tables as $tableName => $fields) {
  3380. //If session is defined, add it to query
  3381. $where = '';
  3382. if (isset($sessionId) && !empty($sessionId)) {
  3383. $sessionField = $fields['session'];
  3384. $where .= " AND $sessionField = $sessionId";
  3385. }
  3386. //filter by date
  3387. if (!empty($date_from) && !empty($date_to)) {
  3388. $fieldStartDate = $fields['start_date'];
  3389. if (!isset($fields['end_date'])) {
  3390. $where .= sprintf(" AND ($fieldStartDate BETWEEN '%s' AND '%s' )", $date_from, $date_to) ;
  3391. } else {
  3392. $fieldEndDate = $fields['end_date'];
  3393. $where .= sprintf(" AND fieldStartDate >= '%s'
  3394. AND $fieldEndDate <= '%s'", $date_from, $date_to);
  3395. }
  3396. }
  3397. //query
  3398. $sql = "SELECT %s as user, count(*) as total
  3399. FROM %s
  3400. WHERE %s = '%s'
  3401. AND %s = %s
  3402. $where
  3403. GROUP BY %s";
  3404. $sql = sprintf($sql,
  3405. $fields['user'], //user field
  3406. $tableName, //FROM
  3407. $fields['course'], //course condition
  3408. $course['code'], //course condition
  3409. $fields['user'], //user condition
  3410. $userId, //user condition
  3411. $fields['user'] //GROUP BY
  3412. );
  3413. $rs = Database::query($sql);
  3414. //iterate query
  3415. if (Database::num_rows($rs) > 0) {
  3416. while ($row = Database::fetch_array($rs)) {
  3417. $data[$row['user']] = (isset($data[$row['user']])) ? $data[$row['user']] + $row[total]: $row['total'];
  3418. }
  3419. }
  3420. }
  3421. return $data;
  3422. }
  3423. /**
  3424. * get documents most downloaded by course
  3425. * @param string Course code
  3426. * @param int Session id (optional), if param $session_id is null(default) it'll return results including sessions, 0 = session is not filtered
  3427. * @param int Limit (optional, default = 0, 0 = without limit)
  3428. * @return array documents downloaded
  3429. */
  3430. public static function get_documents_most_downloaded_by_course($course_code, $session_id = null, $limit = 0)
  3431. {
  3432. //protect data
  3433. $course_code = Database::escape_string($course_code);
  3434. $data = array();
  3435. $TABLETRACK_DOWNLOADS = Database::get_statistic_table(TABLE_STATISTIC_TRACK_E_DOWNLOADS);
  3436. $condition_session = '';
  3437. if (isset($session_id)) {
  3438. $session_id = intval($session_id);
  3439. $condition_session = ' AND down_session_id = '. $session_id;
  3440. }
  3441. $sql = "SELECT down_doc_path, COUNT(DISTINCT down_user_id), COUNT(down_doc_path) as count_down
  3442. FROM $TABLETRACK_DOWNLOADS
  3443. WHERE down_cours_id = '$course_code'
  3444. $condition_session
  3445. GROUP BY down_doc_path
  3446. ORDER BY count_down DESC
  3447. LIMIT 0, $limit";
  3448. $rs = Database::query($sql);
  3449. if (Database::num_rows($rs) > 0) {
  3450. while ($row = Database::fetch_array($rs)) {
  3451. $data[] = $row;
  3452. }
  3453. }
  3454. return $data;
  3455. }
  3456. /**
  3457. * get links most visited by course
  3458. * @param string Course code
  3459. * @param int Session id (optional), if param $session_id is null(default) it'll return results including sessions, 0 = session is not filtered
  3460. * @return array links most visited
  3461. */
  3462. public static function get_links_most_visited_by_course($course_code, $session_id = null)
  3463. {
  3464. $course_code = Database::escape_string($course_code);
  3465. $course_info = api_get_course_info($course_code);
  3466. $course_id = $course_info['real_id'];
  3467. $data = array();
  3468. $TABLETRACK_LINKS = Database::get_statistic_table(TABLE_STATISTIC_TRACK_E_LINKS);
  3469. $TABLECOURSE_LINKS = Database::get_course_table(TABLE_LINK);
  3470. $condition_session = '';
  3471. if (isset($session_id)) {
  3472. $session_id = intval($session_id);
  3473. $condition_session = ' AND cl.session_id = '.$session_id;
  3474. }
  3475. $sql = "SELECT cl.title, cl.url,count(DISTINCT sl.links_user_id), count(cl.title) as count_visits
  3476. FROM $TABLETRACK_LINKS AS sl, $TABLECOURSE_LINKS AS cl
  3477. WHERE cl.c_id = $course_id AND
  3478. sl.links_link_id = cl.id
  3479. AND sl.links_cours_id = '$course_code'
  3480. $condition_session
  3481. GROUP BY cl.title, cl.url
  3482. ORDER BY count_visits DESC
  3483. LIMIT 0, 3";
  3484. $rs = Database::query($sql);
  3485. if (Database::num_rows($rs) > 0) {
  3486. while ($row = Database::fetch_array($rs)) {
  3487. $data[] = $row;
  3488. }
  3489. }
  3490. return $data;
  3491. }
  3492. /**
  3493. * Shows the user progress (when clicking in the Progress tab)
  3494. *
  3495. * @param int $user_id
  3496. * @param int $session_id
  3497. * @param string $extra_params
  3498. * @param bool $show_courses
  3499. *
  3500. * @return string
  3501. */
  3502. public static function show_user_progress($user_id, $session_id = 0, $extra_params = '', $show_courses = true, $showAllSessions = true)
  3503. {
  3504. $tbl_course = Database :: get_main_table(TABLE_MAIN_COURSE);
  3505. $tbl_session = Database :: get_main_table(TABLE_MAIN_SESSION);
  3506. $tbl_course_user = Database :: get_main_table(TABLE_MAIN_COURSE_USER);
  3507. $tbl_access_rel_course = Database :: get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
  3508. $tbl_session_course_user = Database :: get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
  3509. $tbl_access_rel_session = Database :: get_main_table(TABLE_MAIN_ACCESS_URL_REL_SESSION);
  3510. $user_id = intval($user_id);
  3511. if (api_is_multiple_url_enabled()) {
  3512. $sql = "SELECT cu.course_code as code, title
  3513. FROM $tbl_course_user cu INNER JOIN $tbl_access_rel_course a
  3514. ON (a.course_code = cu.course_code)
  3515. INNER JOIN $tbl_course c ON (cu.course_code = c.code)
  3516. WHERE
  3517. user_id = $user_id AND
  3518. relation_type<> ".COURSE_RELATION_TYPE_RRHH." AND
  3519. access_url_id = ".api_get_current_access_url_id()."
  3520. ORDER BY title";
  3521. } else {
  3522. $sql = "SELECT course_code as code, title
  3523. FROM $tbl_course_user u
  3524. INNER JOIN $tbl_course c ON (course_code = c.code)
  3525. WHERE
  3526. u.user_id= $user_id AND
  3527. relation_type<>".COURSE_RELATION_TYPE_RRHH."
  3528. ORDER BY title";
  3529. }
  3530. $rs = Database::query($sql);
  3531. $courses = $course_in_session = $temp_course_in_session = array();
  3532. while($row = Database :: fetch_array($rs, 'ASSOC')) {
  3533. $courses[$row['code']] = $row['title'];
  3534. }
  3535. $orderBy = " ORDER BY name ";
  3536. $extraInnerJoin = null;
  3537. if (SessionManager::orderCourseIsEnabled() && !empty($session_id)) {
  3538. $orderBy = " ORDER BY s.id, position ";
  3539. $tableSessionRelCourse = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
  3540. $extraInnerJoin = " INNER JOIN $tableSessionRelCourse src ON (cu.course_code = src.course_code AND src.id_session = $session_id) ";
  3541. }
  3542. // Get the list of sessions where the user is subscribed as student
  3543. if (api_is_multiple_url_enabled()) {
  3544. $sql = "SELECT DISTINCT cu.course_code, s.id as session_id, name
  3545. FROM $tbl_session_course_user cu
  3546. INNER JOIN $tbl_access_rel_session a
  3547. ON (a.session_id = cu.id_session)
  3548. INNER JOIN $tbl_session s ON (s.id = a.session_id)
  3549. $extraInnerJoin
  3550. WHERE
  3551. id_user = $user_id AND
  3552. access_url_id = ".api_get_current_access_url_id()."
  3553. $orderBy ";
  3554. } else {
  3555. $sql = "SELECT DISTINCT cu.course_code, s.id as session_id, name
  3556. FROM $tbl_session_course_user cu
  3557. INNER JOIN $tbl_session s ON (s.id = cu.id_session)
  3558. $extraInnerJoin
  3559. WHERE id_user = $user_id
  3560. $orderBy ";
  3561. }
  3562. $rs = Database::query($sql);
  3563. $simple_session_array = array();
  3564. while ($row = Database :: fetch_array($rs)) {
  3565. $course_info = CourseManager::get_course_information($row['course_code']);
  3566. $temp_course_in_session[$row['session_id']]['course_list'][$course_info['id']] = $course_info;
  3567. $temp_course_in_session[$row['session_id']]['name'] = $row['name'];
  3568. $simple_session_array[$row['session_id']] = $row['name'];
  3569. }
  3570. foreach ($simple_session_array as $my_session_id => $session_name) {
  3571. $course_list = $temp_course_in_session[$my_session_id]['course_list'];
  3572. $my_course_data = array();
  3573. foreach ($course_list as $course_data) {
  3574. $my_course_data[$course_data['id']] = $course_data['title'];
  3575. }
  3576. if (!SessionManager::orderCourseIsEnabled() && empty($session_id)) {
  3577. $my_course_data = utf8_sort($my_course_data);
  3578. }
  3579. $final_course_data = array();
  3580. foreach($my_course_data as $course_id => $value) {
  3581. $final_course_data[$course_id] = $course_list[$course_id];
  3582. }
  3583. $course_in_session[$my_session_id]['course_list'] = $final_course_data;
  3584. $course_in_session[$my_session_id]['name'] = $session_name;
  3585. }
  3586. $html = '';
  3587. // Course list
  3588. if ($show_courses) {
  3589. if (!empty($courses)) {
  3590. $html .= Display::page_subheader(
  3591. Display::return_icon('course.png', get_lang('MyCourses'), array(), ICON_SIZE_SMALL).' '.get_lang('MyCourses')
  3592. );
  3593. $html .= '<table class="data_table" width="100%">';
  3594. $html .= '<tr>
  3595. '.Display::tag('th', get_lang('Course'), array('width'=>'300px')).'
  3596. '.Display::tag('th', get_lang('TimeSpentInTheCourse'), array('class'=>'head')).'
  3597. '.Display::tag('th', get_lang('Progress'), array('class'=>'head')).'
  3598. '.Display::tag('th', get_lang('Score').Display::return_icon('info3.gif', get_lang('ScormAndLPTestTotalAverage'), array('align' => 'absmiddle', 'hspace' => '3px')),array('class'=>'head')).'
  3599. '.Display::tag('th', get_lang('LastConnexion'), array('class'=>'head')).'
  3600. '.Display::tag('th', get_lang('Details'), array('class'=>'head')).'
  3601. </tr>';
  3602. foreach ($courses as $course_code => $course_title) {
  3603. $total_time_login = Tracking :: get_time_spent_on_the_course(
  3604. $user_id,
  3605. $course_code
  3606. );
  3607. $time = api_time_to_hms($total_time_login);
  3608. $progress = Tracking :: get_avg_student_progress(
  3609. $user_id,
  3610. $course_code
  3611. );
  3612. $percentage_score = Tracking :: get_avg_student_score(
  3613. $user_id,
  3614. $course_code,
  3615. array()
  3616. );
  3617. $last_connection = Tracking :: get_last_connection_date_on_the_course(
  3618. $user_id,
  3619. $course_code
  3620. );
  3621. if (is_null($progress)) {
  3622. $progress = '0%';
  3623. } else {
  3624. $progress = $progress.'%';
  3625. }
  3626. if ($course_code == $_GET['course'] && empty($_GET['session_id'])) {
  3627. $html .= '<tr class="row_odd" style="background-color:#FBF09D">';
  3628. } else {
  3629. $html .= '<tr class="row_even">';
  3630. }
  3631. $url = api_get_course_url($course_code, $session_id);
  3632. $course_url = Display::url($course_title, $url, array('target'=>SESSION_LINK_TARGET));
  3633. $html .= '<td>'.$course_url.'</td>';
  3634. $html .= '<td align="center">'.$time.'</td>';
  3635. $html .= '<td align="center">'.$progress.'</td>';
  3636. $html .= '<td align="center">';
  3637. if (is_numeric($percentage_score)) {
  3638. $html .= $percentage_score.'%';
  3639. } else {
  3640. $html .= '0%';
  3641. }
  3642. $html .= '</td>';
  3643. $html .= '<td align="center">'.$last_connection.'</td>';
  3644. $html .= '<td align="center">';
  3645. if ($course_code == $_GET['course'] && empty($_GET['session_id'])) {
  3646. $html .= '<a href="#">';
  3647. $html .= Display::return_icon('2rightarrow_na.gif', get_lang('Details'));
  3648. } else {
  3649. $html .= '<a href="'.api_get_self().'?course='.$course_code.$extra_params.'">';
  3650. $html .= Display::return_icon('2rightarrow.gif', get_lang('Details'));
  3651. }
  3652. $html .= '</a>';
  3653. $html .= '</td></tr>';
  3654. }
  3655. $html .= '</table>';
  3656. }
  3657. }
  3658. // Session list
  3659. if (!empty($course_in_session)) {
  3660. $main_session_graph = '';
  3661. //Load graphics only when calling to an specific session
  3662. $session_graph = array();
  3663. $all_exercise_graph_name_list = array();
  3664. $my_results = array();
  3665. $all_exercise_graph_list = array();
  3666. $all_exercise_start_time = array();
  3667. foreach ($course_in_session as $my_session_id => $session_data) {
  3668. $course_list = $session_data['course_list'];
  3669. $session_name = $session_data['name'];
  3670. $user_count = count(SessionManager::get_users_by_session($my_session_id));
  3671. $exercise_graph_name_list = array();
  3672. //$user_results = array();
  3673. $exercise_graph_list = array();
  3674. foreach ($course_list as $course_data) {
  3675. $exercise_list = get_all_exercises(
  3676. $course_data,
  3677. $my_session_id,
  3678. false,
  3679. null,
  3680. false,
  3681. 1
  3682. );
  3683. foreach ($exercise_list as $exercise_data) {
  3684. $exercise_obj = new Exercise($course_data['id']);
  3685. $exercise_obj->read($exercise_data['id']);
  3686. //Exercise is not necessary to be visible to show results check the result_disable configuration instead
  3687. //$visible_return = $exercise_obj->is_visible();
  3688. if ($exercise_data['results_disabled'] == 0 || $exercise_data['results_disabled'] == 2) {
  3689. $best_average = intval(
  3690. get_best_average_score_by_exercise(
  3691. $exercise_data['id'],
  3692. $course_data['code'],
  3693. $my_session_id,
  3694. $user_count
  3695. )
  3696. );
  3697. $exercise_graph_list[] = $best_average;
  3698. $all_exercise_graph_list[] = $best_average;
  3699. $user_result_data = get_best_attempt_by_user(
  3700. api_get_user_id(),
  3701. $exercise_data['id'],
  3702. $course_data['code'],
  3703. $my_session_id
  3704. );
  3705. $score = 0;
  3706. if (!empty($user_result_data['exe_weighting']) && intval($user_result_data['exe_weighting']) != 0) {
  3707. $score = intval($user_result_data['exe_result']/$user_result_data['exe_weighting'] * 100);
  3708. }
  3709. $time = api_strtotime($exercise_data['start_time']) ? api_strtotime($exercise_data['start_time'], 'UTC') : 0;
  3710. $all_exercise_start_time[] = $time;
  3711. $my_results[] = $score;
  3712. if (count($exercise_list)<=10) {
  3713. $title = cut($course_data['title'], 30)." \n ".cut($exercise_data['title'], 30);
  3714. $exercise_graph_name_list[]= $title;
  3715. $all_exercise_graph_name_list[] = $title;
  3716. } else {
  3717. // if there are more than 10 results, space becomes difficult to find, so only show the title of the exercise, not the tool
  3718. $title = cut($exercise_data['title'], 30);
  3719. $exercise_graph_name_list[]= $title;
  3720. $all_exercise_graph_name_list[]= $title;
  3721. }
  3722. }
  3723. }
  3724. }
  3725. }
  3726. // Complete graph
  3727. if (!empty($my_results) && !empty($all_exercise_graph_list)) {
  3728. asort($all_exercise_start_time);
  3729. //Fix exams order
  3730. $final_all_exercise_graph_name_list = array();
  3731. $my_results_final = array();
  3732. $final_all_exercise_graph_list = array();
  3733. foreach ($all_exercise_start_time as $key => $time) {
  3734. $label_time = '';
  3735. if (!empty($time)) {
  3736. $label_time = date('d-m-y', $time);
  3737. }
  3738. $final_all_exercise_graph_name_list[] = $all_exercise_graph_name_list[$key].' '.$label_time;
  3739. $my_results_final[] = $my_results[$key];
  3740. $final_all_exercise_graph_list[] = $all_exercise_graph_list[$key];
  3741. }
  3742. $main_session_graph = self::generate_session_exercise_graph(
  3743. $final_all_exercise_graph_name_list,
  3744. $my_results_final,
  3745. $final_all_exercise_graph_list
  3746. );
  3747. }
  3748. $html .= Display::page_subheader(Display::return_icon('session.png', get_lang('Sessions'), array(), ICON_SIZE_SMALL).' '.get_lang('Sessions'));
  3749. $html .= '<table class="data_table" width="100%">';
  3750. $html .= '<tr>
  3751. '.Display::tag('th', get_lang('Session'), array('width'=>'300px')).'
  3752. '.Display::tag('th', get_lang('PublishedExercises'), array('width'=>'300px')).'
  3753. '.Display::tag('th', get_lang('NewExercises'), array('class'=>'head')).'
  3754. '.Display::tag('th', get_lang('AverageExerciseResult'), array('class'=>'head')).'
  3755. '.Display::tag('th', get_lang('Details'), array('class'=>'head')).'
  3756. </tr>';
  3757. foreach ($course_in_session as $my_session_id => $session_data) {
  3758. $course_list = $session_data['course_list'];
  3759. $session_name = $session_data['name'];
  3760. if ($showAllSessions == false) {
  3761. if (isset($session_id) && !empty($session_id)) {
  3762. if ($session_id != $my_session_id) {
  3763. continue;
  3764. }
  3765. }
  3766. }
  3767. $all_exercises = 0;
  3768. $all_unanswered_exercises_by_user = 0;
  3769. $all_average = 0;
  3770. $stats_array = array();
  3771. foreach($course_list as $course_data) {
  3772. //All exercises in the course @todo change for a real count
  3773. $exercises = get_all_exercises($course_data, $my_session_id);
  3774. $count_exercises = 0;
  3775. if (is_array($exercises) && !empty($exercises)) {
  3776. $count_exercises = count($exercises);
  3777. }
  3778. //Count of user results
  3779. //$done_exercises = get_count_exercises_attempted_by_course($course_data['code'], $my_session_id);
  3780. $done_exercises = null;
  3781. $answered_exercises = 0;
  3782. if (!empty($exercises)) {
  3783. foreach($exercises as $exercise_item) {
  3784. $attempts = count_exercise_attempts_by_user(api_get_user_id(), $exercise_item['id'], $course_data['code'], $my_session_id);
  3785. if ($attempts > 1) {
  3786. $answered_exercises++;
  3787. }
  3788. }
  3789. }
  3790. // Average
  3791. $average = get_average_score_by_course($course_data['code'], $my_session_id);
  3792. $all_exercises += $count_exercises;
  3793. $all_unanswered_exercises_by_user += $count_exercises - $answered_exercises;
  3794. //$all_done_exercise += $done_exercises;
  3795. $all_average += $average;
  3796. //$stats_array[$course_data['code']] = array('exercises'=>$count_exercises, 'unanswered_exercises_by_user'=>$answered_exercises,'done_exercises'=>$done_exercises, 'average'=>$average);
  3797. }
  3798. $all_average = $all_average / count($course_list);
  3799. if (isset($_GET['session_id']) && $my_session_id == $_GET['session_id']) {
  3800. $html .= '<tr style="background-color:#FBF09D">';
  3801. } else {
  3802. $html .= '<tr>';
  3803. }
  3804. $url = api_get_path(WEB_CODE_PATH)."session/index.php?session_id={$my_session_id}";
  3805. $html .= Display::tag('td', Display::url($session_name, $url, array('target'=>SESSION_LINK_TARGET)));
  3806. $html .= Display::tag('td', $all_exercises);
  3807. $html .= Display::tag('td', $all_unanswered_exercises_by_user);
  3808. //$html .= Display::tag('td', $all_done_exercise);
  3809. $html .= Display::tag('td', convert_to_percentage($all_average));
  3810. if (isset($_GET['session_id']) && $my_session_id == $_GET['session_id']) {
  3811. $icon = Display::url(Display::return_icon('2rightarrow_na.gif', get_lang('Details')), '?session_id='.$my_session_id);
  3812. } else {
  3813. $icon = Display::url(Display::return_icon('2rightarrow.gif', get_lang('Details')), '?session_id='.$my_session_id);
  3814. }
  3815. $html .= Display::tag('td', $icon);
  3816. $html .= '</tr>';
  3817. }
  3818. $html .= '</table><br />';
  3819. $html .= Display::div($main_session_graph, array('id'=>'session_graph','class'=>'chart-session', 'style'=>'position:relative; text-align: center;') );
  3820. // Checking selected session.
  3821. if (isset($_GET['session_id'])) {
  3822. $session_id_from_get = intval($_GET['session_id']);
  3823. $session_data = $course_in_session[$session_id_from_get];
  3824. $course_list = $session_data['course_list'];
  3825. $html .= Display::tag('h3',$session_data['name'].' - '.get_lang('CourseList'));
  3826. $html .= '<table class="data_table" width="100%">';
  3827. //'.Display::tag('th', get_lang('DoneExercises'), array('class'=>'head')).'
  3828. $html .= '
  3829. <tr>
  3830. <th width="300px">'.get_lang('Course').'</th>
  3831. '.Display::tag('th', get_lang('PublishedExercises'), array('class'=>'head')).'
  3832. '.Display::tag('th', get_lang('NewExercises'), array('class'=>'head')).'
  3833. '.Display::tag('th', get_lang('MyAverage'), array('class'=>'head')).'
  3834. '.Display::tag('th', get_lang('AverageExerciseResult'), array('class'=>'head')).'
  3835. '.Display::tag('th', get_lang('TimeSpentInTheCourse'), array('class'=>'head')).'
  3836. '.Display::tag('th', get_lang('LPProgress') , array('class'=>'head')).'
  3837. '.Display::tag('th', get_lang('Score').Display::return_icon('info3.gif', get_lang('ScormAndLPTestTotalAverage'), array ('align' => 'absmiddle', 'hspace' => '3px')), array('class'=>'head')).'
  3838. '.Display::tag('th', get_lang('LastConnexion'), array('class'=>'head')).'
  3839. '.Display::tag('th', get_lang('Details'), array('class'=>'head')).'
  3840. </tr>';
  3841. foreach ($course_list as $course_data) {
  3842. $course_code = $course_data['code'];
  3843. $course_title = $course_data['title'];
  3844. //All exercises in the course @todo change for a real count
  3845. $exercises = get_all_exercises($course_data, $session_id_from_get);
  3846. $count_exercises = 0;
  3847. if (!empty($exercises)) {
  3848. $count_exercises = count($exercises);
  3849. }
  3850. //Count of user results
  3851. //$done_exercises = get_best_exercise_results_by_course($course_code, $session_id_from_get);
  3852. //From course exercises NOT from LP exercises!!!
  3853. //$done_exercises = get_count_exercises_attempted_by_course($course_code, $session_id_from_get);
  3854. $answered_exercises = 0;
  3855. foreach($exercises as $exercise_item) {
  3856. $attempts = count_exercise_attempts_by_user(api_get_user_id(), $exercise_item['id'], $course_code, $session_id_from_get);
  3857. if ($attempts > 1) {
  3858. $answered_exercises++;
  3859. }
  3860. }
  3861. $unanswered_exercises = $count_exercises - $answered_exercises;
  3862. // Average
  3863. $average = get_average_score_by_course($course_code, $session_id_from_get);
  3864. $my_average = get_average_score_by_course_by_user(api_get_user_id(), $course_code, $session_id_from_get);
  3865. $stats_array[$course_code] = array(
  3866. 'exercises' => $count_exercises,
  3867. 'unanswered_exercises_by_user' => $unanswered_exercises,
  3868. 'done_exercises' => $done_exercises,
  3869. 'average' => $average,
  3870. 'my_average' => $my_average
  3871. );
  3872. $weighting = 0;
  3873. $last_connection = Tracking :: get_last_connection_date_on_the_course($user_id, $course_code, $session_id_from_get);
  3874. $progress = Tracking :: get_avg_student_progress($user_id, $course_code,array(), $session_id_from_get);
  3875. $total_time_login = Tracking :: get_time_spent_on_the_course($user_id, $course_code, $session_id_from_get);
  3876. $time = api_time_to_hms($total_time_login);
  3877. $percentage_score = Tracking :: get_avg_student_score($user_id, $course_code, array(), $session_id_from_get);
  3878. $courseCodeFromGet = isset($_GET['course']) ? $_GET['course'] : null;
  3879. if ($course_code == $courseCodeFromGet && $_GET['session_id'] == $session_id_from_get) {
  3880. $html .= '<tr class="row_odd" style="background-color:#FBF09D" >';
  3881. } else {
  3882. $html .= '<tr class="row_even">';
  3883. }
  3884. $url = api_get_course_url($course_code, $session_id_from_get);
  3885. $course_url = Display::url($course_title, $url, array('target'=>SESSION_LINK_TARGET));
  3886. $html .= Display::tag('td', $course_url);
  3887. $html .= Display::tag('td', $stats_array[$course_code]['exercises']);
  3888. $html .= Display::tag('td', $stats_array[$course_code]['unanswered_exercises_by_user']);
  3889. //$html .= Display::tag('td', $stats_array[$course_code]['done_exercises']);
  3890. $html .= Display::tag('td', convert_to_percentage($stats_array[$course_code]['my_average']));
  3891. $html .= Display::tag('td', $stats_array[$course_code]['average'] == 0 ? '-' : '('.convert_to_percentage($stats_array[$course_code]['average']).')');
  3892. $html .= Display::tag('td', $time, array('align'=>'center'));
  3893. if (is_numeric($progress)) {
  3894. $progress = $progress.'%';
  3895. } else {
  3896. $progress = '0%';
  3897. }
  3898. //Progress
  3899. $html .= Display::tag('td', $progress, array('align'=>'center'));
  3900. if (is_numeric($percentage_score)) {
  3901. $percentage_score = $percentage_score.'%';
  3902. } else {
  3903. $percentage_score = '0%';
  3904. }
  3905. //Score
  3906. $html .= Display::tag('td', $percentage_score, array('align'=>'center'));
  3907. $html .= Display::tag('td', $last_connection, array('align'=>'center'));
  3908. if ($course_code == $courseCodeFromGet && $_GET['session_id'] == $session_id_from_get) {
  3909. $details = '<a href="#">';
  3910. $details .=Display::return_icon('2rightarrow_na.gif', get_lang('Details'));
  3911. } else {
  3912. $details = '<a href="'.api_get_self().'?course='.$course_code.'&session_id='.$session_id_from_get.$extra_params.'">';
  3913. $details .= Display::return_icon('2rightarrow.gif', get_lang('Details'));
  3914. }
  3915. $details .= '</a>';
  3916. $html .= Display::tag('td', $details, array('align'=>'center'));
  3917. $html .= '</tr>';
  3918. }
  3919. $html .= '</table>';
  3920. if (!empty($session_graph[$session_id_from_get])) {
  3921. //$html .= Display::div($session_graph[$session_id_from_get], array('id'=>'session_graph','class'=>'chart-session', 'style'=>'position:relative; text-align: center;') );
  3922. }
  3923. }
  3924. }
  3925. return $html;
  3926. }
  3927. /**
  3928. * Shows the user detail progress (when clicking in the details link)
  3929. * @param int user id
  3930. * @param string course code
  3931. * @param int session id
  3932. * @return string html code
  3933. */
  3934. static function show_course_detail($user_id, $course_code, $session_id)
  3935. {
  3936. $html = '';
  3937. if (isset($course_code)) {
  3938. $user_id = intval($user_id);
  3939. $session_id = intval($session_id);
  3940. $course = Database::escape_string($course_code);
  3941. $course_info = CourseManager::get_course_information($course);
  3942. //$course_id = $course_info['real_id'];
  3943. //$session_name = api_get_session_name($session_id);
  3944. $html .= Display::page_subheader($course_info['title']);
  3945. $html .= '<table class="data_table" width="100%">';
  3946. //Course details
  3947. $html .= '
  3948. <tr>
  3949. <th class="head" style="color:#000">'.get_lang('Exercices').'</th>
  3950. <th class="head" style="color:#000">'.get_lang('Attempts').'</th>
  3951. <th class="head" style="color:#000">'.get_lang('BestAttempt').'</th>
  3952. <th class="head" style="color:#000">'.get_lang('Ranking').'</th>
  3953. <th class="head" style="color:#000">'.get_lang('BestResultInCourse').'</th>
  3954. <th class="head" style="color:#000">'.get_lang('Statistics').' '.Display :: return_icon('info3.gif', get_lang('OnlyBestResultsPerStudent'), array('align' => 'absmiddle', 'hspace' => '3px')).'</th>
  3955. </tr>';
  3956. if (empty($session_id)) {
  3957. $user_list = CourseManager::get_user_list_from_course_code($course, $session_id, null, null, STUDENT);
  3958. } else {
  3959. $user_list = CourseManager::get_user_list_from_course_code($course, $session_id, null, null, 0);
  3960. }
  3961. //$exercise_list = get_all_exercises($course_info, $session_id, true);
  3962. // Show exercise results of invisible exercises? see BT#4091
  3963. $exercise_list = get_all_exercises(
  3964. $course_info,
  3965. $session_id,
  3966. false,
  3967. null,
  3968. false,
  3969. 1
  3970. );
  3971. $to_graph_exercise_result = array();
  3972. if (!empty($exercise_list)) {
  3973. $score = $weighting = $exe_id = 0;
  3974. foreach ($exercise_list as $exercices) {
  3975. $exercise_obj = new Exercise($course_info['real_id']);
  3976. $exercise_obj->read($exercices['id']);
  3977. $visible_return = $exercise_obj->is_visible();
  3978. $score = $weighting = $attempts = 0;
  3979. //Getting count of attempts by user
  3980. $attempts = count_exercise_attempts_by_user(api_get_user_id(), $exercices['id'], $course_info['code'], $session_id);
  3981. $html .= '<tr class="row_even">';
  3982. $url = api_get_path(WEB_CODE_PATH)."exercice/overview.php?cidReq={$course_info['code']}&id_session=$session_id&exerciseId={$exercices['id']}";
  3983. if ($visible_return['value'] == true) {
  3984. $exercices['title'] = Display::url($exercices['title'], $url, array('target'=>SESSION_LINK_TARGET));
  3985. }
  3986. $html .= Display::tag('td', $exercices['title']);
  3987. //Exercise configuration show results or show only score
  3988. if ($exercices['results_disabled'] == 0 || $exercices['results_disabled'] == 2) {
  3989. //For graphics
  3990. $best_exercise_stats = get_best_exercise_results_by_user($exercices['id'], $course_info['code'], $session_id);
  3991. $to_graph_exercise_result[$exercices['id']] = array('title'=>$exercices['title'], 'data'=>$best_exercise_stats);
  3992. $latest_attempt_url = '';
  3993. $best_score = $position = $percentage_score_result = '-';
  3994. $graph = $normal_graph = null;
  3995. //Getting best results
  3996. $best_score_data = get_best_attempt_in_course($exercices['id'], $course_info['code'], $session_id);
  3997. $best_score = show_score($best_score_data['exe_result'], $best_score_data['exe_weighting']);
  3998. if ($attempts > 0) {
  3999. $exercise_stat = get_best_attempt_by_user(api_get_user_id(), $exercices['id'], $course_info['code'], $session_id);
  4000. if (!empty($exercise_stat)) {
  4001. //Always getting the BEST attempt
  4002. $score = $exercise_stat['exe_result'];
  4003. $weighting = $exercise_stat['exe_weighting'];
  4004. $exe_id = $exercise_stat['exe_id'];
  4005. $latest_attempt_url .= api_get_path(WEB_CODE_PATH).'exercice/result.php?id='.$exe_id.'&cidReq='.$course_info['code'].'&show_headers=1&id_session='.$session_id;
  4006. $percentage_score_result = Display::url(show_score($score, $weighting), $latest_attempt_url);
  4007. $my_score = 0;
  4008. if (!empty($weighting) && intval($weighting) != 0) {
  4009. $my_score = $score/$weighting;
  4010. }
  4011. //@todo this function slows the page
  4012. $position = get_exercise_result_ranking($my_score, $exe_id, $exercices['id'], $course_info['code'], $session_id, $user_list);
  4013. $graph = self::generate_exercise_result_thumbnail_graph($to_graph_exercise_result[$exercices['id']]);
  4014. $normal_graph = self::generate_exercise_result_graph($to_graph_exercise_result[$exercices['id']]);
  4015. }
  4016. }
  4017. $html .= Display::div($normal_graph, array('id'=>'main_graph_'.$exercices['id'],'class'=>'dialog', 'style'=>'display:none') );
  4018. if (empty($graph)) {
  4019. $graph = '-';
  4020. } else {
  4021. $graph = Display::url($graph, '#', array('id'=>$exercices['id'], 'class'=>'opener'));
  4022. }
  4023. $html .= Display::tag('td', $attempts, array('align'=>'center'));
  4024. $html .= Display::tag('td', $percentage_score_result, array('align'=>'center'));
  4025. $html .= Display::tag('td', $position, array('align'=>'center'));
  4026. $html .= Display::tag('td', $best_score, array('align'=>'center'));
  4027. $html .= Display::tag('td', $graph, array('align'=>'center'));
  4028. //$html .= Display::tag('td', $latest_attempt_url, array('align'=>'center', 'width'=>'25'));
  4029. } else {
  4030. // Exercise configuration NO results
  4031. $html .= Display::tag('td', $attempts, array('align'=>'center'));
  4032. $html .= Display::tag('td', '-', array('align'=>'center'));
  4033. $html .= Display::tag('td', '-', array('align'=>'center'));
  4034. $html .= Display::tag('td', '-', array('align'=>'center'));
  4035. $html .= Display::tag('td', '-', array('align'=>'center'));
  4036. }
  4037. $html .= '</tr>';
  4038. }
  4039. } else {
  4040. $html .= '<tr><td colspan="5" align="center">'.get_lang('NoEx').'</td></tr>';
  4041. }
  4042. $html .= '</table>';
  4043. //LP table results
  4044. $html .='<table class="data_table">';
  4045. $html .= Display::tag('th', get_lang('Learnpaths'), array('class'=>'head', 'style'=>'color:#000'));
  4046. $html .= Display::tag('th', get_lang('LatencyTimeSpent'), array('class'=>'head', 'style'=>'color:#000'));
  4047. $html .= Display::tag('th', get_lang('Progress'), array('class'=>'head', 'style'=>'color:#000'));
  4048. $html .= Display::tag('th', get_lang('Score'), array('class'=>'head', 'style'=>'color:#000'));
  4049. $html .= Display::tag('th', get_lang('LastConnexion'), array('class'=>'head', 'style'=>'color:#000'));
  4050. $html .= '</tr>';
  4051. $list = new LearnpathList(api_get_user_id(), $course_info['code'], $session_id, 'publicated_on ASC', true);
  4052. $lp_list = $list->get_flat_list();
  4053. if (!empty($lp_list) > 0) {
  4054. foreach($lp_list as $lp_id => $learnpath) {
  4055. $progress = Tracking::get_avg_student_progress($user_id, $course, array($lp_id), $session_id);
  4056. $last_connection_in_lp = Tracking::get_last_connection_time_in_lp($user_id, $course, $lp_id, $session_id);
  4057. $time_spent_in_lp = Tracking::get_time_spent_in_lp($user_id, $course, array($lp_id), $session_id);
  4058. $percentage_score = Tracking::get_avg_student_score($user_id, $course, array($lp_id), $session_id);
  4059. if (is_numeric($percentage_score)) {
  4060. $percentage_score = $percentage_score.'%';
  4061. } else {
  4062. $percentage_score = '0%';
  4063. }
  4064. $time_spent_in_lp = api_time_to_hms($time_spent_in_lp);
  4065. $html .= '<tr class="row_even">';
  4066. $url = api_get_path(WEB_CODE_PATH)."newscorm/lp_controller.php?cidReq={$course_code}&id_session=$session_id&lp_id=$lp_id&action=view";
  4067. $html .= Display::tag('td', Display::url($learnpath['lp_name'], $url, array('target'=>SESSION_LINK_TARGET)));
  4068. $html .= Display::tag('td', $time_spent_in_lp, array('align'=>'center'));
  4069. if (is_numeric($progress)) {
  4070. $progress = $progress.'%';
  4071. }
  4072. $html .= Display::tag('td', $progress, array('align'=>'center'));
  4073. $html .= Display::tag('td', $percentage_score);
  4074. $last_connection = '-';
  4075. if (!empty($last_connection_in_lp)) {
  4076. $last_connection = api_convert_and_format_date($last_connection_in_lp, DATE_TIME_FORMAT_LONG);
  4077. }
  4078. $html .= Display::tag('td', $last_connection, array('align'=>'center','width'=>'180px'));
  4079. $html .= "</tr>";
  4080. }
  4081. } else {
  4082. $html .= '<tr>
  4083. <td colspan="4" align="center">
  4084. '.get_lang('NoLearnpath').'
  4085. </td>
  4086. </tr>';
  4087. }
  4088. $html .='</table>';
  4089. }
  4090. return $html;
  4091. }
  4092. /**
  4093. * Generates an histogram
  4094. * @param array list of exercise names
  4095. * @param array my results 0 to 100
  4096. * @param array average scores 0-100
  4097. * @return string
  4098. */
  4099. static function generate_session_exercise_graph($names, $my_results, $average)
  4100. {
  4101. /* Create and populate the pData object */
  4102. $myData = new pData();
  4103. $myData->addPoints($names, 'Labels');
  4104. $myData->addPoints($my_results, 'Serie1');
  4105. $myData->addPoints($average, 'Serie2');
  4106. $myData->setSerieWeight('Serie1', 1);
  4107. $myData->setSerieTicks('Serie2', 4);
  4108. $myData->setSerieDescription('Labels', 'Months');
  4109. $myData->setAbscissa('Labels');
  4110. $myData->setSerieDescription('Serie1', get_lang('MyResults'));
  4111. $myData->setSerieDescription('Serie2', get_lang('AverageScore'));
  4112. $myData->setAxisUnit(0, '%');
  4113. $myData->loadPalette(api_get_path(SYS_CODE_PATH) . 'palettes/pchart/default.color', true);
  4114. // Cache definition
  4115. $cachePath = api_get_path(SYS_ARCHIVE_PATH);
  4116. $myCache = new pCache(array('CacheFolder' => substr($cachePath, 0, strlen($cachePath) - 1)));
  4117. $chartHash = $myCache->getHash($myData);
  4118. if ($myCache->isInCache($chartHash)) {
  4119. //if we already created the img
  4120. $imgPath = api_get_path(SYS_ARCHIVE_PATH) . $chartHash;
  4121. $myCache->saveFromCache($chartHash, $imgPath);
  4122. $imgPath = api_get_path(WEB_ARCHIVE_PATH) . $chartHash;
  4123. } else {
  4124. /* Define width, height and angle */
  4125. $mainWidth = 860;
  4126. $mainHeight = 500;
  4127. $angle = 50;
  4128. /* Create the pChart object */
  4129. $myPicture = new pImage($mainWidth, $mainHeight, $myData);
  4130. /* Turn of Antialiasing */
  4131. $myPicture->Antialias = false;
  4132. /* Draw the background */
  4133. $settings = array('R' => 255, 'G' => 255, 'B' => 255);
  4134. $myPicture->drawFilledRectangle(0, 0, $mainWidth, $mainHeight, $settings);
  4135. /* Add a border to the picture */
  4136. $myPicture->drawRectangle(
  4137. 0,
  4138. 0,
  4139. $mainWidth - 1,
  4140. $mainHeight - 1,
  4141. array('R' => 0, 'G' => 0, 'B' => 0)
  4142. );
  4143. /* Set the default font */
  4144. $myPicture->setFontProperties(
  4145. array(
  4146. 'FontName' => api_get_path(SYS_FONTS_PATH) . 'opensans/OpenSans-Regular.ttf',
  4147. 'FontSize' => 10)
  4148. );
  4149. /* Write the chart title */
  4150. $myPicture->drawText(
  4151. $mainWidth / 2,
  4152. 30,
  4153. get_lang('ExercisesInTimeProgressChart'),
  4154. array(
  4155. 'FontSize' => 12,
  4156. 'Align' => TEXT_ALIGN_BOTTOMMIDDLE
  4157. )
  4158. );
  4159. /* Set the default font */
  4160. $myPicture->setFontProperties(
  4161. array(
  4162. 'FontName' => api_get_path(SYS_FONTS_PATH) . 'opensans/OpenSans-Regular.ttf',
  4163. 'FontSize' => 6
  4164. )
  4165. );
  4166. /* Define the chart area */
  4167. $myPicture->setGraphArea(60, 60, $mainWidth - 60, $mainHeight - 150);
  4168. /* Draw the scale */
  4169. $scaleSettings = array(
  4170. 'XMargin' => 10,
  4171. 'YMargin' => 10,
  4172. 'Floating' => true,
  4173. 'GridR' => 200,
  4174. 'GridG' => 200,
  4175. 'GridB' => 200,
  4176. 'DrawSubTicks' => true,
  4177. 'CycleBackground' => true,
  4178. 'LabelRotation' => $angle,
  4179. 'Mode' => SCALE_MODE_ADDALL_START0,
  4180. );
  4181. $myPicture->drawScale($scaleSettings);
  4182. /* Turn on Antialiasing */
  4183. $myPicture->Antialias = true;
  4184. /* Enable shadow computing */
  4185. $myPicture->setShadow(
  4186. true,
  4187. array(
  4188. 'X' => 1,
  4189. 'Y' => 1,
  4190. 'R' => 0,
  4191. 'G' => 0,
  4192. 'B' => 0,
  4193. 'Alpha' => 10
  4194. )
  4195. );
  4196. /* Draw the line chart */
  4197. $myPicture->setFontProperties(
  4198. array(
  4199. 'FontName' => api_get_path(SYS_FONTS_PATH) . 'opensans/OpenSans-Regular.ttf',
  4200. 'FontSize' => 10
  4201. )
  4202. );
  4203. $myPicture->drawSplineChart();
  4204. $myPicture->drawPlotChart(
  4205. array(
  4206. 'DisplayValues' => true,
  4207. 'PlotBorder' => true,
  4208. 'BorderSize' => 1,
  4209. 'Surrounding' => -60,
  4210. 'BorderAlpha' => 80
  4211. )
  4212. );
  4213. /* Write the chart legend */
  4214. $myPicture->drawLegend(
  4215. $mainWidth / 2 + 50,
  4216. 50,
  4217. array(
  4218. 'Style' => LEGEND_BOX,
  4219. 'Mode' => LEGEND_HORIZONTAL,
  4220. 'FontR' => 0,
  4221. 'FontG' => 0,
  4222. 'FontB' => 0,
  4223. 'R' => 220,
  4224. 'G' => 220,
  4225. 'B' => 220,
  4226. 'Alpha' => 100
  4227. )
  4228. );
  4229. $myCache->writeToCache($chartHash, $myPicture);
  4230. $imgPath = api_get_path(SYS_ARCHIVE_PATH) . $chartHash;
  4231. $myCache->saveFromCache($chartHash, $imgPath);
  4232. $imgPath = api_get_path(WEB_ARCHIVE_PATH) . $chartHash;
  4233. }
  4234. $html = '<img src="' . $imgPath . '">';
  4235. return $html;
  4236. }
  4237. /**
  4238. *
  4239. * Returns a thumbnail of the function generate_exercise_result_graph
  4240. * @param array attempts
  4241. */
  4242. static function generate_exercise_result_thumbnail_graph($attempts)
  4243. {
  4244. $exercise_title = $attempts['title'];
  4245. $attempts = $attempts['data'];
  4246. $my_exercise_result_array = $exercise_result = array();
  4247. if (empty($attempts)) {
  4248. return null;
  4249. }
  4250. foreach ($attempts as $attempt) {
  4251. if (api_get_user_id() == $attempt['exe_user_id']) {
  4252. if ($attempt['exe_weighting'] != 0 ) {
  4253. $my_exercise_result_array[]= $attempt['exe_result']/$attempt['exe_weighting'];
  4254. }
  4255. } else {
  4256. if ($attempt['exe_weighting'] != 0 ) {
  4257. $exercise_result[]= $attempt['exe_result']/$attempt['exe_weighting'];
  4258. }
  4259. }
  4260. }
  4261. //Getting best result
  4262. rsort($my_exercise_result_array);
  4263. $my_exercise_result = 0;
  4264. if (isset($my_exercise_result_array[0])) {
  4265. $my_exercise_result = $my_exercise_result_array[0] *100;
  4266. }
  4267. $max = 100;
  4268. $pieces = 5 ;
  4269. $part = round($max / $pieces);
  4270. $x_axis = array();
  4271. $final_array = array();
  4272. $my_final_array = array();
  4273. for ($i=1; $i <=$pieces; $i++) {
  4274. $sum = 1;
  4275. if ($i == 1) {
  4276. $sum = 0;
  4277. }
  4278. $min = ($i-1)*$part + $sum;
  4279. $max = ($i)*$part;
  4280. $x_axis[]= $min." - ".$max;
  4281. $count = 0;
  4282. foreach($exercise_result as $result) {
  4283. $percentage = $result*100;
  4284. //echo $percentage.' - '.$min.' - '.$max."<br />";
  4285. if ($percentage >= $min && $percentage <= $max) {
  4286. //echo ' is > ';
  4287. $count++;
  4288. }
  4289. }
  4290. //echo '<br />';
  4291. $final_array[]= $count;
  4292. if ($my_exercise_result >= $min && $my_exercise_result <= $max) {
  4293. $my_final_array[] = 1;
  4294. } else {
  4295. $my_final_array[] = 0;
  4296. }
  4297. }
  4298. //Fix to remove the data of the user with my data
  4299. for($i = 0; $i<=count($my_final_array); $i++) {
  4300. if (!empty($my_final_array[$i])) {
  4301. $my_final_array[$i] = $final_array[$i] + 1; //Add my result
  4302. $final_array[$i] = 0;
  4303. }
  4304. }
  4305. // Dataset definition
  4306. $dataSet = new pData();
  4307. $dataSet->addPoints($final_array, 'Serie1');
  4308. $dataSet->addPoints($my_final_array, 'Serie2');
  4309. $dataSet->normalize(100, "%");
  4310. $dataSet->loadPalette(api_get_path(SYS_CODE_PATH) . 'palettes/pchart/default.color', true);
  4311. // Cache definition
  4312. $cachePath = api_get_path(SYS_ARCHIVE_PATH);
  4313. $myCache = new pCache(array('CacheFolder' => substr($cachePath, 0, strlen($cachePath) - 1)));
  4314. $chartHash = $myCache->getHash($dataSet);
  4315. if ($myCache->isInCache($chartHash)) {
  4316. $imgPath = api_get_path(SYS_ARCHIVE_PATH) . $chartHash;
  4317. $myCache->saveFromCache($chartHash, $imgPath);
  4318. $imgPath = api_get_path(WEB_ARCHIVE_PATH) . $chartHash;
  4319. } else {
  4320. /* Create the pChart object */
  4321. $widthSize = 80;
  4322. $heightSize = 35;
  4323. $fontSize = 2;
  4324. $myPicture = new pImage($widthSize, $heightSize, $dataSet);
  4325. /* Turn of Antialiasing */
  4326. $myPicture->Antialias = false;
  4327. /* Add a border to the picture */
  4328. $myPicture->drawRectangle(0, 0, $widthSize - 1, $heightSize - 1, array('R' => 0, 'G' => 0, 'B' => 0));
  4329. /* Set the default font */
  4330. $myPicture->setFontProperties(array('FontName' => api_get_path(SYS_FONTS_PATH) . 'opensans/OpenSans-Regular.ttf', 'FontSize' => $fontSize));
  4331. /* Do not write the chart title */
  4332. /* Define the chart area */
  4333. $myPicture->setGraphArea(5, 5, $widthSize - 5, $heightSize - 5);
  4334. /* Draw the scale */
  4335. $scaleSettings = array(
  4336. 'GridR' => 200,
  4337. 'GridG' => 200,
  4338. 'GridB' => 200,
  4339. 'DrawSubTicks' => true,
  4340. 'CycleBackground' => true,
  4341. 'Mode' => SCALE_MODE_MANUAL,
  4342. 'ManualScale' => array(
  4343. '0' => array(
  4344. 'Min' => 0,
  4345. 'Max' => 100
  4346. )
  4347. )
  4348. );
  4349. $myPicture->drawScale($scaleSettings);
  4350. /* Turn on shadow computing */
  4351. $myPicture->setShadow(
  4352. true,
  4353. array(
  4354. 'X' => 1,
  4355. 'Y' => 1,
  4356. 'R' => 0,
  4357. 'G' => 0,
  4358. 'B' => 0,
  4359. 'Alpha' => 10
  4360. )
  4361. );
  4362. /* Draw the chart */
  4363. $myPicture->setShadow(
  4364. true,
  4365. array(
  4366. 'X' => 1,
  4367. 'Y' => 1,
  4368. 'R' => 0,
  4369. 'G' => 0,
  4370. 'B' => 0,
  4371. 'Alpha' => 10
  4372. )
  4373. );
  4374. $settings = array(
  4375. 'DisplayValues' => true,
  4376. 'DisplaySize' => $fontSize,
  4377. 'DisplayR' => 0,
  4378. 'DisplayG' => 0,
  4379. 'DisplayB' => 0,
  4380. 'DisplayOrientation' => ORIENTATION_HORIZONTAL,
  4381. 'Gradient' => false,
  4382. 'Surrounding' => 5,
  4383. 'InnerSurrounding' => 5
  4384. );
  4385. $myPicture->drawStackedBarChart($settings);
  4386. /* Save and write in cache */
  4387. $myCache->writeToCache($chartHash, $myPicture);
  4388. $imgPath = api_get_path(SYS_ARCHIVE_PATH) . $chartHash;
  4389. $myCache->saveFromCache($chartHash, $imgPath);
  4390. $imgPath = api_get_path(WEB_ARCHIVE_PATH) . $chartHash;
  4391. }
  4392. $html = '<img src="' . $imgPath . '" >';
  4393. return $html;
  4394. }
  4395. /**
  4396. * Generates a big graph with the number of best results
  4397. * @param array
  4398. */
  4399. static function generate_exercise_result_graph($attempts)
  4400. {
  4401. $exercise_title = strip_tags($attempts['title']);
  4402. $attempts = $attempts['data'];
  4403. $my_exercise_result_array = $exercise_result = array();
  4404. if (empty($attempts)) {
  4405. return null;
  4406. }
  4407. foreach ($attempts as $attempt) {
  4408. if (api_get_user_id() == $attempt['exe_user_id']) {
  4409. if ($attempt['exe_weighting'] != 0 ) {
  4410. $my_exercise_result_array[]= $attempt['exe_result']/$attempt['exe_weighting'];
  4411. }
  4412. } else {
  4413. if ($attempt['exe_weighting'] != 0 ) {
  4414. $exercise_result[]= $attempt['exe_result']/$attempt['exe_weighting'];
  4415. }
  4416. }
  4417. }
  4418. //Getting best result
  4419. rsort($my_exercise_result_array);
  4420. $my_exercise_result = 0;
  4421. if (isset($my_exercise_result_array[0])) {
  4422. $my_exercise_result = $my_exercise_result_array[0] *100;
  4423. }
  4424. $max = 100;
  4425. $pieces = 5 ;
  4426. $part = round($max / $pieces);
  4427. $x_axis = array();
  4428. $final_array = array();
  4429. $my_final_array = array();
  4430. for ($i=1; $i <=$pieces; $i++) {
  4431. $sum = 1;
  4432. if ($i == 1) {
  4433. $sum = 0;
  4434. }
  4435. $min = ($i-1)*$part + $sum;
  4436. $max = ($i)*$part;
  4437. $x_axis[]= $min." - ".$max;
  4438. $count = 0;
  4439. foreach($exercise_result as $result) {
  4440. $percentage = $result*100;
  4441. //echo $percentage.' - '.$min.' - '.$max."<br />";
  4442. if ($percentage >= $min && $percentage <= $max) {
  4443. //echo ' is > ';
  4444. $count++;
  4445. }
  4446. }
  4447. //echo '<br />';
  4448. $final_array[]= $count;
  4449. if ($my_exercise_result >= $min && $my_exercise_result <= $max) {
  4450. $my_final_array[] = 1;
  4451. } else {
  4452. $my_final_array[] = 0;
  4453. }
  4454. }
  4455. //Fix to remove the data of the user with my data
  4456. for($i = 0; $i<=count($my_final_array); $i++) {
  4457. if (!empty($my_final_array[$i])) {
  4458. $my_final_array[$i] = $final_array[$i] + 1; //Add my result
  4459. $final_array[$i] = 0;
  4460. }
  4461. }
  4462. // Dataset definition
  4463. $dataSet = new pData();
  4464. $dataSet->addPoints($final_array, 'Serie1');
  4465. $dataSet->addPoints($my_final_array, 'Serie2');
  4466. $dataSet->addPoints($x_axis, 'Serie3');
  4467. $dataSet->setSerieDescription('Serie1', get_lang('Score'));
  4468. $dataSet->setSerieDescription('Serie2', get_lang('MyResults'));
  4469. $dataSet->setAbscissa('Serie3');
  4470. $dataSet->setXAxisName(get_lang('Score'));
  4471. $dataSet->normalize(100, "%");
  4472. $dataSet->loadPalette(api_get_path(SYS_CODE_PATH) . 'palettes/pchart/default.color', true);
  4473. // Cache definition
  4474. $cachePath = api_get_path(SYS_ARCHIVE_PATH);
  4475. $myCache = new pCache(array('CacheFolder' => substr($cachePath, 0, strlen($cachePath) - 1)));
  4476. $chartHash = $myCache->getHash($dataSet);
  4477. if ($myCache->isInCache($chartHash)) {
  4478. $imgPath = api_get_path(SYS_ARCHIVE_PATH) . $chartHash;
  4479. $myCache->saveFromCache($chartHash, $imgPath);
  4480. $imgPath = api_get_path(WEB_ARCHIVE_PATH) . $chartHash;
  4481. } else {
  4482. /* Create the pChart object */
  4483. $widthSize = 480;
  4484. $heightSize = 250;
  4485. $fontSize = 8;
  4486. $myPicture = new pImage($widthSize, $heightSize, $dataSet);
  4487. /* Turn of Antialiasing */
  4488. $myPicture->Antialias = false;
  4489. /* Add a border to the picture */
  4490. $myPicture->drawRectangle(0, 0, $widthSize - 1, $heightSize - 1, array('R' => 0, 'G' => 0, 'B' => 0));
  4491. /* Set the default font */
  4492. $myPicture->setFontProperties(array('FontName' => api_get_path(SYS_FONTS_PATH) . 'opensans/OpenSans-Regular.ttf', 'FontSize' => 10));
  4493. /* Write the chart title */
  4494. $myPicture->drawText(
  4495. 250,
  4496. 20,
  4497. $exercise_title,
  4498. array(
  4499. 'FontSize' => 12,
  4500. 'Align' => TEXT_ALIGN_BOTTOMMIDDLE
  4501. )
  4502. );
  4503. /* Define the chart area */
  4504. $myPicture->setGraphArea(50, 50, $widthSize - 20, $heightSize - 30);
  4505. /* Draw the scale */
  4506. $scaleSettings = array(
  4507. 'GridR' => 200,
  4508. 'GridG' => 200,
  4509. 'GridB' => 200,
  4510. 'DrawSubTicks' => true,
  4511. 'CycleBackground' => true,
  4512. 'Mode' => SCALE_MODE_MANUAL,
  4513. 'ManualScale' => array(
  4514. '0' => array(
  4515. 'Min' => 0,
  4516. 'Max' => 100
  4517. )
  4518. )
  4519. );
  4520. $myPicture->drawScale($scaleSettings);
  4521. /* Turn on shadow computing */
  4522. $myPicture->setShadow(true, array('X' => 1, 'Y' => 1, 'R' => 0, 'G' => 0, 'B' => 0, 'Alpha' => 10));
  4523. /* Draw the chart */
  4524. $myPicture->setShadow(true, array('X' => 1, 'Y' => 1, 'R' => 0, 'G' => 0, 'B' => 0, 'Alpha' => 10));
  4525. $settings = array(
  4526. 'DisplayValues' => true,
  4527. 'DisplaySize' => $fontSize,
  4528. 'DisplayR' => 0,
  4529. 'DisplayG' => 0,
  4530. 'DisplayB' => 0,
  4531. 'DisplayOrientation' => ORIENTATION_HORIZONTAL,
  4532. 'Gradient' => false,
  4533. 'Surrounding' => 30,
  4534. 'InnerSurrounding' => 25
  4535. );
  4536. $myPicture->drawStackedBarChart($settings);
  4537. $legendSettings = array(
  4538. 'Mode' => LEGEND_HORIZONTAL,
  4539. 'Style' => LEGEND_NOBORDER,
  4540. );
  4541. $myPicture->drawLegend($widthSize / 2, 30, $legendSettings);
  4542. /* Write and save into cache */
  4543. $myCache->writeToCache($chartHash, $myPicture);
  4544. $imgPath = api_get_path(SYS_ARCHIVE_PATH) . $chartHash;
  4545. $myCache->saveFromCache($chartHash, $imgPath);
  4546. $imgPath = api_get_path(WEB_ARCHIVE_PATH) . $chartHash;
  4547. }
  4548. $html = '<img src="' . $imgPath . '" >';
  4549. return $html;
  4550. }
  4551. /**
  4552. * @param FormValidator $form
  4553. * @return mixed
  4554. */
  4555. public static function setUserSearchForm($form)
  4556. {
  4557. global $_configuration;
  4558. $form->addElement('text', 'keyword', get_lang('Keyword'));
  4559. $form->addElement('select', 'active', get_lang('Status'), array(1 => get_lang('Active'), 0 => get_lang('Inactive')));
  4560. if (isset($_configuration['save_user_last_login']) &&
  4561. $_configuration['save_user_last_login']
  4562. ) {
  4563. $form->addElement(
  4564. 'select',
  4565. 'sleeping_days',
  4566. get_lang('InactiveDays'),
  4567. array('', 1 => 1, 5 => 5, 15 => 15, 30 => 30, 60 => 60, 90 => 90, 120 => 120)
  4568. );
  4569. }
  4570. $form->addElement('button', 'submit', get_lang('Search'));
  4571. return $form;
  4572. }
  4573. /**
  4574. * Get the progress of a exercise
  4575. * @param int $sessionId The session ID (session.id)
  4576. * @param int $courseId The course ID (course.id)
  4577. * @param int $exerciseId The quiz ID (c_quiz.id)
  4578. * @param int $answer The answer status (0 = incorrect, 1 = correct, 2 = both)
  4579. * @param array $options An array of options you can pass to the query (limit, where and order)
  4580. * @return array An array with the data of exercise(s) progress
  4581. */
  4582. public static function get_exercise_progress(
  4583. $sessionId = 0,
  4584. $courseId = 0,
  4585. $exerciseId = 0,
  4586. $date_from = null,
  4587. $date_to = null,
  4588. $options = array()
  4589. ) {
  4590. $sessionId = intval($sessionId);
  4591. $courseId = intval($courseId);
  4592. $exerciseId = intval($exerciseId);
  4593. $date_from = Database::escape_string($date_from);
  4594. $date_to = Database::escape_string($date_to);
  4595. /*
  4596. * This method gets the data by blocks, as previous attempts at one single
  4597. * query made it take ages. The logic of query division is described below
  4598. */
  4599. // Get tables names
  4600. $tuser = Database::get_main_table(TABLE_MAIN_USER);
  4601. $tquiz = Database::get_course_table(TABLE_QUIZ_TEST);
  4602. $tquiz_answer = Database::get_course_table(TABLE_QUIZ_ANSWER);
  4603. $tquiz_question = Database::get_course_table(TABLE_QUIZ_QUESTION);
  4604. $tquiz_rel_question = Database::get_course_table(TABLE_QUIZ_TEST_QUESTION);
  4605. $ttrack_exercises = Database::get_statistic_table(TABLE_STATISTIC_TRACK_E_EXERCICES);
  4606. $ttrack_attempt = Database::get_statistic_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
  4607. require_once api_get_path(SYS_CODE_PATH).'exercice/exercise.lib.php';
  4608. $sessions = array();
  4609. $courses = array();
  4610. // if session ID is defined but course ID is empty, get all the courses
  4611. // from that session
  4612. if (!empty($sessionId) && empty($courseId)) {
  4613. // $courses is an array of course int id as index and course details hash as value
  4614. $courses = SessionManager::get_course_list_by_session_id($sessionId);
  4615. $sessions[$sessionId] = api_get_session_info($sessionId);
  4616. } elseif (empty($sessionId) && !empty($courseId)) {
  4617. // if, to the contrary, course is defined but not sessions, get the sessions that include this course
  4618. // $sessions is an array like: [0] => ('id' => 3, 'name' => 'Session 35'), [1] => () etc;
  4619. $course = api_get_course_info_by_id($courseId);
  4620. $sessionsTemp = SessionManager::get_session_by_course($course['code']);
  4621. $courses[$courseId] = $course;
  4622. foreach ($sessionsTemp as $sessionItem) {
  4623. $sessions[$sessionItem['id']] = $sessionItem;
  4624. }
  4625. } elseif (!empty($courseId) && !empty($sessionId)) {
  4626. //none is empty
  4627. $course = api_get_course_info_by_id($courseId);
  4628. $courses[$courseId] = array($course['code']);
  4629. $courses[$courseId]['code'] = $course['code'];
  4630. $sessions[$sessionId] = api_get_session_info($sessionId);
  4631. } else {
  4632. //both are empty, not enough data, return an empty array
  4633. return array();
  4634. }
  4635. // Now we have two arrays of courses and sessions with enough data to proceed
  4636. // If no course could be found, we shouldn't return anything. Sessions can be empty (then we only return the pure-course-context results)
  4637. if (count($courses) < 1) {
  4638. return array();
  4639. }
  4640. $data = array();
  4641. // The following loop is less expensive than what it seems:
  4642. // - if a course was defined, then we only loop through sessions
  4643. // - if a session was defined, then we only loop through courses
  4644. // - if a session and a course were defined, then we only loop once
  4645. foreach ($courses as $courseIdx => $courseData) {
  4646. $where = '';
  4647. $whereParams = array();
  4648. $whereCourseCode = $courseData['code'];
  4649. $whereSessionParams = '';
  4650. if (count($sessions > 0)) {
  4651. foreach ($sessions as $sessionIdx => $sessionData) {
  4652. if (!empty($sessionIdx)) {
  4653. $whereSessionParams .= $sessionIdx.',';
  4654. }
  4655. }
  4656. $whereSessionParams = substr($whereSessionParams,0,-1);
  4657. }
  4658. if (!empty($exerciseId)) {
  4659. $exerciseId = intval($exerciseId);
  4660. $where .= ' AND q.id = %d ';
  4661. $whereParams[] = $exerciseId;
  4662. }
  4663. /*
  4664. * This feature has been disabled for now, to avoid having to
  4665. * join two very large tables
  4666. //2 = show all questions (wrong and correct answered)
  4667. if ($answer != 2) {
  4668. $answer = intval($answer);
  4669. //$where .= ' AND qa.correct = %d';
  4670. //$whereParams[] = $answer;
  4671. }
  4672. */
  4673. $limit = '';
  4674. if (!empty($options['limit'])) {
  4675. $limit = " LIMIT ".$options['limit'];
  4676. }
  4677. if (!empty($options['where'])) {
  4678. $where .= ' AND '.Database::escape_string($options['where']);
  4679. }
  4680. $order = '';
  4681. if (!empty($options['order'])) {
  4682. $order = " ORDER BY ".$options['order'];
  4683. }
  4684. if (!empty($date_to) && !empty($date_from)) {
  4685. $where .= sprintf(" AND (te.start_date BETWEEN '%s 00:00:00' AND '%s 23:59:59')", $date_from, $date_to);
  4686. }
  4687. $sql = "SELECT
  4688. te.session_id,
  4689. ta.id as attempt_id,
  4690. te.exe_user_id as user_id,
  4691. te.exe_id as exercise_attempt_id,
  4692. ta.question_id,
  4693. ta.answer as answer_id,
  4694. ta.tms as time,
  4695. te.exe_exo_id as quiz_id,
  4696. CONCAT ('c', q.c_id, '_e', q.id) as exercise_id,
  4697. q.title as quiz_title,
  4698. qq.description as description
  4699. FROM $ttrack_exercises te
  4700. INNER JOIN $ttrack_attempt ta ON ta.exe_id = te.exe_id
  4701. INNER JOIN $tquiz q ON q.id = te.exe_exo_id
  4702. INNER JOIN $tquiz_rel_question rq ON rq.exercice_id = q.id AND rq.c_id = q.c_id
  4703. INNER JOIN $tquiz_question qq
  4704. ON
  4705. qq.id = rq.question_id AND
  4706. qq.c_id = rq.c_id AND
  4707. qq.position = rq.question_order AND
  4708. ta.question_id = rq.question_id
  4709. WHERE
  4710. te.exe_cours_id = '$whereCourseCode' ".(empty($whereSessionParams)?'':"AND te.session_id IN ($whereSessionParams)")."
  4711. AND q.c_id = $courseIdx
  4712. $where $order $limit";
  4713. $sql_query = vsprintf($sql, $whereParams);
  4714. // Now browse through the results and get the data
  4715. $rs = Database::query($sql_query);
  4716. $userIds = array();
  4717. $questionIds = array();
  4718. $answerIds = array();
  4719. while ($row = Database::fetch_array($rs)) {
  4720. //only show if exercise is visible
  4721. if (api_get_item_visibility($courseData, 'quiz', $row['exercise_id'])) {
  4722. $userIds[$row['user_id']] = $row['user_id'];
  4723. $questionIds[$row['question_id']] = $row['question_id'];
  4724. $answerIds[$row['question_id']][$row['answer_id']] = $row['answer_id'];
  4725. $row['session'] = $sessions[$row['session_id']];
  4726. $data[] = $row;
  4727. }
  4728. }
  4729. // Now fill questions data. Query all questions and answers for this test to avoid
  4730. $sqlQuestions = "SELECT tq.c_id, tq.id as question_id, tq.question, tqa.id_auto,
  4731. tqa.answer, tqa.correct, tq.position, tqa.id_auto as answer_id
  4732. FROM $tquiz_question tq, $tquiz_answer tqa
  4733. WHERE
  4734. tqa.question_id = tq.id AND
  4735. tqa.c_id = tq.c_id AND
  4736. tq.c_id = $courseIdx AND
  4737. tq.id IN (".implode(',', $questionIds).")";
  4738. $resQuestions = Database::query($sqlQuestions);
  4739. $answer = array();
  4740. $question = array();
  4741. while ($rowQuestion = Database::fetch_assoc($resQuestions)) {
  4742. $questionId = $rowQuestion['question_id'];
  4743. $answerId = $rowQuestion['answer_id'];
  4744. $answer[$questionId][$answerId] = array(
  4745. 'position' => $rowQuestion['position'],
  4746. 'question' => $rowQuestion['question'],
  4747. 'answer' => $rowQuestion['answer'],
  4748. 'correct' => $rowQuestion['correct']
  4749. );
  4750. $question[$questionId]['question'] = $rowQuestion['question'];
  4751. }
  4752. // Now fill users data
  4753. $sqlUsers = "SELECT user_id, username, lastname, firstname
  4754. FROM $tuser
  4755. WHERE user_id IN (".implode(',',$userIds).")";
  4756. $resUsers = Database::query($sqlUsers);
  4757. while ($rowUser = Database::fetch_assoc($resUsers)) {
  4758. $users[$rowUser['user_id']] = $rowUser;
  4759. }
  4760. foreach ($data as $id => $row) {
  4761. $rowQuestId = $row['question_id'];
  4762. $rowAnsId = $row['answer_id'];
  4763. $data[$id]['session'] = $sessions[$row['session_id']]['name'];
  4764. $data[$id]['firstname'] = $users[$row['user_id']]['firstname'];
  4765. $data[$id]['lastname'] = $users[$row['user_id']]['lastname'];
  4766. $data[$id]['username'] = $users[$row['user_id']]['username'];
  4767. $data[$id]['answer'] = $answer[$rowQuestId][$rowAnsId]['answer'];
  4768. $data[$id]['correct'] = ($answer[$rowQuestId][$rowAnsId]['correct'] == 0 ? get_lang('No') : get_lang('Yes'));
  4769. $data[$id]['question'] = $question[$rowQuestId]['question'];
  4770. $data[$id]['question_id'] = $rowQuestId;
  4771. $data[$id]['description'] = $row['description'];
  4772. }
  4773. /*
  4774. The minimum expected array structure at the end is:
  4775. attempt_id,
  4776. session name,
  4777. exercise_id,
  4778. quiz_title,
  4779. username,
  4780. lastname,
  4781. firstname,
  4782. time,
  4783. question_id,
  4784. question,
  4785. answer,
  4786. */
  4787. }
  4788. return $data;
  4789. }
  4790. }
  4791. /**
  4792. * @todo move into a proper file
  4793. * @package chamilo.tracking
  4794. */
  4795. class TrackingCourseLog
  4796. {
  4797. /**
  4798. * @return mixed
  4799. */
  4800. public static function count_item_resources()
  4801. {
  4802. $session_id = api_get_session_id();
  4803. $course_id = api_get_course_int_id();
  4804. $table_item_property = Database :: get_course_table(TABLE_ITEM_PROPERTY);
  4805. $table_user = Database :: get_main_table(TABLE_MAIN_USER);
  4806. $sql = "SELECT count(tool) AS total_number_of_items
  4807. FROM $table_item_property track_resource, $table_user user
  4808. WHERE
  4809. track_resource.c_id = $course_id AND
  4810. track_resource.insert_user_id = user.user_id AND
  4811. id_session = $session_id ";
  4812. if (isset($_GET['keyword'])) {
  4813. $keyword = Database::escape_string(trim($_GET['keyword']));
  4814. $sql .= " AND (
  4815. user.username LIKE '%".$keyword."%' OR
  4816. lastedit_type LIKE '%".$keyword."%' OR
  4817. tool LIKE '%".$keyword."%'
  4818. )";
  4819. }
  4820. $sql .= " AND tool IN (
  4821. 'document',
  4822. 'learnpath',
  4823. 'quiz',
  4824. 'glossary',
  4825. 'link',
  4826. 'course_description',
  4827. 'announcement',
  4828. 'thematic',
  4829. 'thematic_advance',
  4830. 'thematic_plan'
  4831. )";
  4832. $res = Database::query($sql);
  4833. $obj = Database::fetch_object($res);
  4834. return $obj->total_number_of_items;
  4835. }
  4836. /**
  4837. * @param $from
  4838. * @param $number_of_items
  4839. * @param $column
  4840. * @param $direction
  4841. * @return array
  4842. */
  4843. public static function get_item_resources_data($from, $number_of_items, $column, $direction)
  4844. {
  4845. $session_id = api_get_session_id();
  4846. $course_id = api_get_course_int_id();
  4847. $table_item_property = Database :: get_course_table(TABLE_ITEM_PROPERTY);
  4848. $table_user = Database :: get_main_table(TABLE_MAIN_USER);
  4849. $table_session = Database :: get_main_table(TABLE_MAIN_SESSION);
  4850. $session_id = intval($session_id);
  4851. $sql = "SELECT
  4852. tool as col0,
  4853. lastedit_type as col1,
  4854. ref as ref,
  4855. user.username as col3,
  4856. insert_date as col5,
  4857. visibility as col6,
  4858. user.user_id as user_id
  4859. FROM $table_item_property track_resource, $table_user user
  4860. WHERE
  4861. track_resource.c_id = $course_id AND
  4862. track_resource.insert_user_id = user.user_id AND
  4863. id_session = $session_id ";
  4864. if (isset($_GET['keyword'])) {
  4865. $keyword = Database::escape_string(trim($_GET['keyword']));
  4866. $sql .= " AND (
  4867. user.username LIKE '%".$keyword."%' OR
  4868. lastedit_type LIKE '%".$keyword."%' OR
  4869. tool LIKE '%".$keyword."%'
  4870. ) ";
  4871. }
  4872. $sql .= " AND tool IN (
  4873. 'document',
  4874. 'learnpath',
  4875. 'quiz',
  4876. 'glossary',
  4877. 'link',
  4878. 'course_description',
  4879. 'announcement',
  4880. 'thematic',
  4881. 'thematic_advance',
  4882. 'thematic_plan'
  4883. )";
  4884. if ($column == 0) {
  4885. $column = '0';
  4886. }
  4887. if ($column != '' && $direction != '') {
  4888. if ($column != 2 && $column != 4) {
  4889. $sql .= " ORDER BY col$column $direction";
  4890. }
  4891. } else {
  4892. $sql .= " ORDER BY col5 DESC ";
  4893. }
  4894. $from = intval($from);
  4895. $number_of_items = intval($number_of_items);
  4896. $sql .= " LIMIT $from, $number_of_items ";
  4897. $res = Database::query($sql);
  4898. $resources = array();
  4899. $thematic_tools = array('thematic', 'thematic_advance', 'thematic_plan');
  4900. while ($row = Database::fetch_array($res)) {
  4901. $ref = $row['ref'];
  4902. $table_name = TrackingCourseLog::get_tool_name_table($row['col0']);
  4903. $table_tool = Database :: get_course_table($table_name['table_name']);
  4904. $id = $table_name['id_tool'];
  4905. $recorset = false;
  4906. if (in_array($row['col0'], array('thematic_plan', 'thematic_advance'))) {
  4907. $tbl_thematic = Database :: get_course_table(TABLE_THEMATIC);
  4908. $sql = "SELECT thematic_id FROM $table_tool WHERE c_id = $course_id AND id = $ref";
  4909. $rs_thematic = Database::query($sql);
  4910. if (Database::num_rows($rs_thematic)) {
  4911. $row_thematic = Database::fetch_array($rs_thematic);
  4912. $thematic_id = $row_thematic['thematic_id'];
  4913. $sql = "SELECT session.id, session.name, user.username
  4914. FROM $tbl_thematic t, $table_session session, $table_user user
  4915. WHERE
  4916. t.c_id = $course_id AND
  4917. t.session_id = session.id AND
  4918. session.id_coach = user.user_id AND
  4919. t.id = $thematic_id";
  4920. $recorset = Database::query($sql);
  4921. }
  4922. } else {
  4923. $sql = "SELECT session.id, session.name, user.username
  4924. FROM $table_tool tool, $table_session session, $table_user user
  4925. WHERE
  4926. tool.c_id = $course_id AND
  4927. tool.session_id = session.id AND
  4928. session.id_coach = user.user_id AND
  4929. tool.$id = $ref";
  4930. $recorset = Database::query($sql);
  4931. }
  4932. if (!empty($recorset)) {
  4933. $obj = Database::fetch_object($recorset);
  4934. $name_session = '';
  4935. $coach_name = '';
  4936. if (!empty($obj)) {
  4937. $name_session = $obj->name;
  4938. $coach_name = $obj->username;
  4939. }
  4940. $url_tool = api_get_path(WEB_CODE_PATH).$table_name['link_tool'];
  4941. $row[0] = '';
  4942. if ($row['col6'] != 2) {
  4943. if (in_array($row['col0'], $thematic_tools)) {
  4944. $exp_thematic_tool = explode('_', $row['col0']);
  4945. $thematic_tool_title = '';
  4946. if (is_array($exp_thematic_tool)) {
  4947. foreach ($exp_thematic_tool as $exp) {
  4948. $thematic_tool_title .= api_ucfirst($exp);
  4949. }
  4950. } else {
  4951. $thematic_tool_title = api_ucfirst($row['col0']);
  4952. }
  4953. $row[0] = '<a href="'.$url_tool.'?'.api_get_cidreq().'&action=thematic_details">'.get_lang($thematic_tool_title).'</a>';
  4954. } else {
  4955. $row[0] = '<a href="'.$url_tool.'?'.api_get_cidreq().'">'.get_lang('Tool'.api_ucfirst($row['col0'])).'</a>';
  4956. }
  4957. } else {
  4958. $row[0] = api_ucfirst($row['col0']);
  4959. }
  4960. $row[1] = get_lang($row[1]);
  4961. $row[6] = api_convert_and_format_date($row['col5'], null, date_default_timezone_get());
  4962. $row[5] = '';
  4963. //@todo Improve this code please
  4964. switch ($table_name['table_name']) {
  4965. case 'document' :
  4966. $sql = "SELECT tool.title as title FROM $table_tool tool
  4967. WHERE c_id = $course_id AND id = $ref";
  4968. $rs_document = Database::query($sql);
  4969. $obj_document = Database::fetch_object($rs_document);
  4970. $row[5] = $obj_document->title;
  4971. break;
  4972. case 'announcement':
  4973. $sql = "SELECT title FROM $table_tool
  4974. WHERE c_id = $course_id AND id = $ref";
  4975. $rs_document = Database::query($sql);
  4976. $obj_document = Database::fetch_object($rs_document);
  4977. $row[5] = $obj_document->title;
  4978. break;
  4979. case 'glossary':
  4980. $sql = "SELECT name FROM $table_tool
  4981. WHERE c_id = $course_id AND glossary_id = $ref";
  4982. $rs_document = Database::query($sql);
  4983. $obj_document = Database::fetch_object($rs_document);
  4984. $row[5] = $obj_document->name;
  4985. break;
  4986. case 'lp':
  4987. $sql = "SELECT name
  4988. FROM $table_tool WHERE c_id = $course_id AND id = $ref";
  4989. $rs_document = Database::query($sql);
  4990. $obj_document = Database::fetch_object($rs_document);
  4991. $row[5] = $obj_document->name;
  4992. break;
  4993. case 'quiz':
  4994. $sql = "SELECT title FROM $table_tool
  4995. WHERE c_id = $course_id AND id = $ref";
  4996. $rs_document = Database::query($sql);
  4997. $obj_document = Database::fetch_object($rs_document);
  4998. $row[5] = $obj_document->title;
  4999. break;
  5000. case 'course_description':
  5001. $sql = "SELECT title FROM $table_tool
  5002. WHERE c_id = $course_id AND id = $ref";
  5003. $rs_document = Database::query($sql);
  5004. $obj_document = Database::fetch_object($rs_document);
  5005. $row[5] = $obj_document->title;
  5006. break;
  5007. case 'thematic':
  5008. $rs = Database::query("SELECT title FROM $table_tool WHERE c_id = $course_id AND id = $ref");
  5009. if (Database::num_rows($rs) > 0) {
  5010. $obj = Database::fetch_object($rs);
  5011. $row[5] = $obj->title;
  5012. }
  5013. break;
  5014. case 'thematic_advance':
  5015. $rs = Database::query("SELECT content FROM $table_tool WHERE c_id = $course_id AND id = $ref");
  5016. if (Database::num_rows($rs) > 0) {
  5017. $obj = Database::fetch_object($rs);
  5018. $row[5] = $obj->content;
  5019. }
  5020. break;
  5021. case 'thematic_plan':
  5022. $rs = Database::query("SELECT title FROM $table_tool WHERE c_id = $course_id AND id = $ref");
  5023. if (Database::num_rows($rs) > 0) {
  5024. $obj = Database::fetch_object($rs);
  5025. $row[5] = $obj->title;
  5026. }
  5027. break;
  5028. default:
  5029. break;
  5030. }
  5031. $row2 = $name_session;
  5032. if (!empty($coach_name)) {
  5033. $row2 .= '<br />'.get_lang('Coach').': '.$coach_name;
  5034. }
  5035. $row[2] = $row2;
  5036. if (!empty($row['col3'])) {
  5037. $row['col3'] = Display::url(
  5038. $row['col3'],
  5039. api_get_path(WEB_CODE_PATH).'user/userInfo.php?'.api_get_cidreq().'&origin=tracking&uInfo='.$row['user_id']
  5040. );
  5041. $row[3] = $row['col3'];
  5042. $ip = TrackingUserLog::get_ip_from_user_event($row['user_id'], $row['col5'], true);
  5043. if (empty($ip)) {
  5044. $ip = get_lang('Unknown');
  5045. }
  5046. $row[4] = $ip;
  5047. }
  5048. $resources[] = $row;
  5049. }
  5050. }
  5051. return $resources;
  5052. }
  5053. /**
  5054. * @param string $tool
  5055. *
  5056. * @return array
  5057. */
  5058. public static function get_tool_name_table($tool)
  5059. {
  5060. switch ($tool) {
  5061. case 'document':
  5062. $table_name = TABLE_DOCUMENT;
  5063. $link_tool = 'document/document.php';
  5064. $id_tool = 'id';
  5065. break;
  5066. case 'learnpath':
  5067. $table_name = TABLE_LP_MAIN;
  5068. $link_tool = 'newscorm/lp_controller.php';
  5069. $id_tool = 'id';
  5070. break;
  5071. case 'quiz':
  5072. $table_name = TABLE_QUIZ_TEST;
  5073. $link_tool = 'exercice/exercice.php';
  5074. $id_tool = 'id';
  5075. break;
  5076. case 'glossary':
  5077. $table_name = TABLE_GLOSSARY;
  5078. $link_tool = 'glossary/index.php';
  5079. $id_tool = 'glossary_id';
  5080. break;
  5081. case 'link':
  5082. $table_name = TABLE_LINK;
  5083. $link_tool = 'link/link.php';
  5084. $id_tool = 'id';
  5085. break;
  5086. case 'course_description':
  5087. $table_name = TABLE_COURSE_DESCRIPTION;
  5088. $link_tool = 'course_description/';
  5089. $id_tool = 'id';
  5090. break;
  5091. case 'announcement':
  5092. $table_name = TABLE_ANNOUNCEMENT;
  5093. $link_tool = 'announcements/announcements.php';
  5094. $id_tool = 'id';
  5095. break;
  5096. case 'thematic':
  5097. $table_name = TABLE_THEMATIC;
  5098. $link_tool = 'course_progress/index.php';
  5099. $id_tool = 'id';
  5100. break;
  5101. case 'thematic_advance':
  5102. $table_name = TABLE_THEMATIC_ADVANCE;
  5103. $link_tool = 'course_progress/index.php';
  5104. $id_tool = 'id';
  5105. break;
  5106. case 'thematic_plan':
  5107. $table_name = TABLE_THEMATIC_PLAN;
  5108. $link_tool = 'course_progress/index.php';
  5109. $id_tool = 'id';
  5110. break;
  5111. default:
  5112. $table_name = $tool;
  5113. break;
  5114. }
  5115. return array(
  5116. 'table_name' => $table_name,
  5117. 'link_tool' => $link_tool,
  5118. 'id_tool' => $id_tool
  5119. );
  5120. }
  5121. public static function display_additional_profile_fields()
  5122. {
  5123. // getting all the extra profile fields that are defined by the platform administrator
  5124. $extra_fields = UserManager :: get_extra_fields(0,50,5,'ASC');
  5125. // creating the form
  5126. $return = '<form action="courseLog.php" method="get" name="additional_profile_field_form" id="additional_profile_field_form">';
  5127. // the select field with the additional user profile fields (= this is where we select the field of which we want to see
  5128. // the information the users have entered or selected.
  5129. $return .= '<select name="additional_profile_field">';
  5130. $return .= '<option value="-">'.get_lang('SelectFieldToAdd').'</option>';
  5131. $extra_fields_to_show = 0;
  5132. foreach ($extra_fields as $key=>$field) {
  5133. // show only extra fields that are visible + and can be filtered, added by J.Montoya
  5134. if ($field[6]==1 && $field[8] == 1) {
  5135. if (isset($_GET['additional_profile_field']) && $field[0] == $_GET['additional_profile_field'] ) {
  5136. $selected = 'selected="selected"';
  5137. } else {
  5138. $selected = '';
  5139. }
  5140. $extra_fields_to_show++;
  5141. $return .= '<option value="'.$field[0].'" '.$selected.'>'.$field[3].'</option>';
  5142. }
  5143. }
  5144. $return .= '</select>';
  5145. // the form elements for the $_GET parameters (because the form is passed through GET
  5146. foreach ($_GET as $key=>$value){
  5147. if ($key <> 'additional_profile_field') {
  5148. $return .= '<input type="hidden" name="'.Security::remove_XSS($key).'" value="'.Security::remove_XSS($value).'" />';
  5149. }
  5150. }
  5151. // the submit button
  5152. $return .= '<button class="save" type="submit">'.get_lang('AddAdditionalProfileField').'</button>';
  5153. $return .= '</form>';
  5154. if ($extra_fields_to_show > 0) {
  5155. return $return;
  5156. } else {
  5157. return '';
  5158. }
  5159. }
  5160. /**
  5161. * This function gets all the information of a certrain ($field_id) additional profile field.
  5162. * It gets the information of all the users so that it can be displayed in the sortable table or in the csv or xls export
  5163. *
  5164. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University, Belgium
  5165. * @since October 2009
  5166. * @version 1.8.7
  5167. */
  5168. public function get_addtional_profile_information_of_field($field_id)
  5169. {
  5170. // Database table definition
  5171. $table_user = Database::get_main_table(TABLE_MAIN_USER);
  5172. $table_user_field_values = Database::get_main_table(TABLE_MAIN_USER_FIELD_VALUES);
  5173. $sql = "SELECT user.user_id, field.field_value
  5174. FROM $table_user user, $table_user_field_values field
  5175. WHERE
  5176. user.user_id = field.user_id AND
  5177. field.field_id='".intval($field_id)."'";
  5178. $result = Database::query($sql);
  5179. while($row = Database::fetch_array($result)) {
  5180. $return[$row['user_id']][] = $row['field_value'];
  5181. }
  5182. return $return;
  5183. }
  5184. /**
  5185. * This function gets all the information of a certrain ($field_id)
  5186. * additional profile field for a specific list of users is more efficent
  5187. * than get_addtional_profile_information_of_field() function
  5188. * It gets the information of all the users so that it can be displayed
  5189. * in the sortable table or in the csv or xls export
  5190. *
  5191. * @author Julio Montoya <gugli100@gmail.com>
  5192. * @param int field id
  5193. * @param array list of user ids
  5194. * @return array
  5195. * @since Nov 2009
  5196. * @version 1.8.6.2
  5197. */
  5198. public static function get_addtional_profile_information_of_field_by_user($field_id, $users)
  5199. {
  5200. // Database table definition
  5201. $table_user = Database::get_main_table(TABLE_MAIN_USER);
  5202. $table_user_field_values = Database::get_main_table(TABLE_MAIN_USER_FIELD_VALUES);
  5203. $result_extra_field = UserManager::get_extra_field_information($field_id);
  5204. if (!empty($users)) {
  5205. if ($result_extra_field['field_type'] == UserManager::USER_FIELD_TYPE_TAG ) {
  5206. foreach($users as $user_id) {
  5207. $user_result = UserManager::get_user_tags($user_id, $field_id);
  5208. $tag_list = array();
  5209. foreach($user_result as $item) {
  5210. $tag_list[] = $item['tag'];
  5211. }
  5212. $return[$user_id][] = implode(', ',$tag_list);
  5213. }
  5214. } else {
  5215. $new_user_array = array();
  5216. foreach($users as $user_id) {
  5217. $new_user_array[]= "'".$user_id."'";
  5218. }
  5219. $users = implode(',',$new_user_array);
  5220. //selecting only the necessary information NOT ALL the user list
  5221. $sql = "SELECT user.user_id, field.field_value FROM $table_user user INNER JOIN $table_user_field_values field
  5222. ON (user.user_id = field.user_id)
  5223. WHERE field.field_id=".intval($field_id)." AND user.user_id IN ($users)";
  5224. $result = Database::query($sql);
  5225. while($row = Database::fetch_array($result)) {
  5226. // get option value for field type double select by id
  5227. if (!empty($row['field_value'])) {
  5228. if ($result_extra_field['field_type'] == USER_FIELD_TYPE_DOUBLE_SELECT) {
  5229. $id_double_select = explode(';',$row['field_value']);
  5230. if (is_array($id_double_select)) {
  5231. $value1 = $result_extra_field['options'][$id_double_select[0]]['option_value'];
  5232. $value2 = $result_extra_field['options'][$id_double_select[1]]['option_value'];
  5233. $row['field_value'] = ($value1.';'.$value2);
  5234. }
  5235. }
  5236. }
  5237. // get other value from extra field
  5238. $return[$row['user_id']][] = $row['field_value'];
  5239. }
  5240. }
  5241. }
  5242. return $return;
  5243. }
  5244. /**
  5245. * count the number of students in this course (used for SortableTable)
  5246. * Deprecated
  5247. */
  5248. public function count_student_in_course()
  5249. {
  5250. global $nbStudents;
  5251. return $nbStudents;
  5252. }
  5253. public function sort_users($a, $b)
  5254. {
  5255. return strcmp(trim(api_strtolower($a[$_SESSION['tracking_column']])), trim(api_strtolower($b[$_SESSION['tracking_column']])));
  5256. }
  5257. public function sort_users_desc($a, $b)
  5258. {
  5259. return strcmp( trim(api_strtolower($b[$_SESSION['tracking_column']])), trim(api_strtolower($a[$_SESSION['tracking_column']])));
  5260. }
  5261. /**
  5262. * Get number of users for sortable with pagination
  5263. * @return int
  5264. */
  5265. public static function get_number_of_users()
  5266. {
  5267. global $user_ids;
  5268. return count($user_ids);
  5269. }
  5270. /**
  5271. * Get data for users list in sortable with pagination
  5272. * @param $from
  5273. * @param $number_of_items
  5274. * @param $column
  5275. * @param $direction
  5276. * @return array
  5277. */
  5278. public static function get_user_data($from, $number_of_items, $column, $direction)
  5279. {
  5280. global $user_ids, $course_code, $additional_user_profile_info, $export_csv, $is_western_name_order, $csv_content, $session_id;
  5281. $course_code = Database::escape_string($course_code);
  5282. $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
  5283. $tbl_url_rel_user = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
  5284. $access_url_id = api_get_current_access_url_id();
  5285. // get all users data from a course for sortable with limit
  5286. if (is_array($user_ids)) {
  5287. $user_ids = array_map('intval', $user_ids);
  5288. $condition_user = " WHERE user.user_id IN (".implode(',',$user_ids).") ";
  5289. } else {
  5290. $user_ids = intval($user_ids);
  5291. $condition_user = " WHERE user.user_id = $user_ids ";
  5292. }
  5293. if (!empty($_GET['user_keyword'])) {
  5294. $keyword = trim(Database::escape_string($_GET['user_keyword']));
  5295. $condition_user .= " AND (
  5296. user.firstname LIKE '%".$keyword."%' OR
  5297. user.lastname LIKE '%".$keyword."%' OR
  5298. user.username LIKE '%".$keyword."%' OR
  5299. user.email LIKE '%".$keyword."%'
  5300. ) ";
  5301. }
  5302. $url_table = null;
  5303. $url_condition = null;
  5304. if (api_is_multiple_url_enabled()) {
  5305. $url_table = ", ".$tbl_url_rel_user."as url_users";
  5306. $url_condition = " AND user.user_id = url_users.user_id AND access_url_id='$access_url_id'";
  5307. }
  5308. $sql = "SELECT user.user_id as user_id,
  5309. user.official_code as col0,
  5310. user.lastname as col1,
  5311. user.firstname as col2,
  5312. user.username as col3
  5313. FROM $tbl_user as user $url_table
  5314. $condition_user $url_condition";
  5315. if (!in_array($direction, array('ASC','DESC'))) {
  5316. $direction = 'ASC';
  5317. }
  5318. $column = intval($column);
  5319. $from = intval($from);
  5320. $number_of_items = intval($number_of_items);
  5321. $sql .= " ORDER BY col$column $direction ";
  5322. $sql .= " LIMIT $from,$number_of_items";
  5323. $res = Database::query($sql);
  5324. $users = array();
  5325. $course_info = api_get_course_info($course_code);
  5326. $total_surveys = 0;
  5327. $total_exercises = get_all_exercises(
  5328. $course_info,
  5329. $session_id,
  5330. false,
  5331. null,
  5332. false,
  5333. 3
  5334. );
  5335. if (empty($session_id)) {
  5336. $survey_user_list = array();
  5337. $survey_list = survey_manager::get_surveys($course_code, $session_id);
  5338. $total_surveys = count($survey_list);
  5339. foreach ($survey_list as $survey) {
  5340. $user_list = survey_manager::get_people_who_filled_survey(
  5341. $survey['survey_id'],
  5342. false,
  5343. $course_info['real_id']
  5344. );
  5345. foreach ($user_list as $user_id) {
  5346. isset($survey_user_list[$user_id]) ? $survey_user_list[$user_id]++ : $survey_user_list[$user_id] = 1;
  5347. }
  5348. }
  5349. }
  5350. while ($user = Database::fetch_array($res, 'ASSOC')) {
  5351. $user['official_code'] = $user['col0'];
  5352. $user['lastname'] = $user['col1'];
  5353. $user['firstname'] = $user['col2'];
  5354. $user['username'] = $user['col3'];
  5355. $user['time'] = api_time_to_hms(Tracking::get_time_spent_on_the_course($user['user_id'], $course_code, $session_id));
  5356. $avg_student_score = Tracking::get_avg_student_score(
  5357. $user['user_id'],
  5358. $course_code,
  5359. array(),
  5360. $session_id
  5361. );
  5362. $avg_student_progress = Tracking::get_avg_student_progress(
  5363. $user['user_id'],
  5364. $course_code,
  5365. array(),
  5366. $session_id
  5367. );
  5368. if (empty($avg_student_progress)) {
  5369. $avg_student_progress=0;
  5370. }
  5371. $user['average_progress'] = $avg_student_progress.'%';
  5372. $total_user_exercise = Tracking::get_exercise_student_progress(
  5373. $total_exercises,
  5374. $user['user_id'],
  5375. $course_code,
  5376. $session_id
  5377. );
  5378. $user['exercise_progress'] = $total_user_exercise;
  5379. $total_user_exercise = Tracking::get_exercise_student_average_best_attempt(
  5380. $total_exercises,
  5381. $user['user_id'],
  5382. $course_code,
  5383. $session_id
  5384. );
  5385. $user['exercise_average_best_attempt'] = $total_user_exercise;
  5386. if (is_numeric($avg_student_score)) {
  5387. $user['student_score'] = $avg_student_score.'%';
  5388. } else {
  5389. $user['student_score'] = $avg_student_score;
  5390. }
  5391. $user['count_assignments'] = Tracking::count_student_assignments($user['user_id'], $course_code, $session_id);
  5392. $user['count_messages'] = Tracking::count_student_messages($user['user_id'], $course_code, $session_id);
  5393. $user['first_connection'] = Tracking::get_first_connection_date_on_the_course($user['user_id'], $course_code, $session_id);
  5394. $user['last_connection'] = Tracking::get_last_connection_date_on_the_course($user['user_id'], $course_code, $session_id);
  5395. // we need to display an additional profile field
  5396. $user['additional'] = '';
  5397. if (isset($_GET['additional_profile_field']) AND is_numeric($_GET['additional_profile_field'])) {
  5398. if (isset($additional_user_profile_info[$user['user_id']]) &&
  5399. is_array($additional_user_profile_info[$user['user_id']])
  5400. ) {
  5401. $user['additional'] = implode(', ', $additional_user_profile_info[$user['user_id']]);
  5402. }
  5403. }
  5404. if (empty($session_id)) {
  5405. $user['survey'] = (isset($survey_user_list[$user['user_id']]) ? $survey_user_list[$user['user_id']] : 0) .' / '.$total_surveys;
  5406. }
  5407. $user['link'] = '<center><a href="../mySpace/myStudents.php?student='.$user['user_id'].'&details=true&course='.$course_code.'&origin=tracking_course&id_session='.$session_id.'"><img src="'.api_get_path(WEB_IMG_PATH).'2rightarrow.gif" border="0" /></a></center>';
  5408. // store columns in array $users
  5409. $is_western_name_order = api_is_western_name_order();
  5410. $user_row = array();
  5411. $user_row[]= $user['official_code']; //0
  5412. if ($is_western_name_order) {
  5413. $user_row[]= $user['firstname'];
  5414. $user_row[]= $user['lastname'];
  5415. } else {
  5416. $user_row[]= $user['lastname'];
  5417. $user_row[]= $user['firstname'];
  5418. }
  5419. $user_row[]= $user['username'];
  5420. $user_row[]= $user['time'];
  5421. $user_row[]= $user['average_progress'];
  5422. $user_row[]= $user['exercise_progress'];
  5423. $user_row[]= $user['exercise_average_best_attempt'];
  5424. $user_row[]= $user['student_score'];
  5425. $user_row[]= $user['count_assignments'];
  5426. $user_row[]= $user['count_messages'];
  5427. if (empty($session_id)) {
  5428. $user_row[]= $user['survey'];
  5429. }
  5430. $user_row[]= $user['first_connection'];
  5431. $user_row[]= $user['last_connection'];
  5432. if (isset($_GET['additional_profile_field']) AND is_numeric($_GET['additional_profile_field'])) {
  5433. $user_row[]= $user['additional'];
  5434. }
  5435. $user_row[]= $user['link'];
  5436. $users[] = $user_row;
  5437. if ($export_csv) {
  5438. if (empty($session_id)) {
  5439. $user_row = array_map('strip_tags', $user_row);
  5440. unset($user_row[14]);
  5441. unset($user_row[15]);
  5442. } else {
  5443. $user_row = array_map('strip_tags', $user_row);
  5444. unset($user_row[13]);
  5445. unset($user_row[14]);
  5446. }
  5447. $csv_content[] = $user_row;
  5448. }
  5449. }
  5450. return $users;
  5451. }
  5452. }
  5453. /**
  5454. * @package chamilo.tracking
  5455. */
  5456. class TrackingUserLog
  5457. {
  5458. /**
  5459. * Displays the number of logins every month for a specific user in a specific course.
  5460. */
  5461. public function display_login_tracking_info($view, $user_id, $course_id, $session_id = 0)
  5462. {
  5463. $MonthsLong = $GLOBALS['MonthsLong'];
  5464. // protected data
  5465. $user_id = intval($user_id);
  5466. $session_id = intval($session_id);
  5467. $course_id = Database::escape_string($course_id);
  5468. $track_access_table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ACCESS);
  5469. $tempView = $view;
  5470. if(substr($view,0,1) == '1') {
  5471. $new_view = substr_replace($view,'0',0,1);
  5472. echo "
  5473. <tr>
  5474. <td valign='top'>
  5475. <font color='#0000FF'>-&nbsp;&nbsp;&nbsp;</font>" .
  5476. "<b>".get_lang('LoginsAndAccessTools')."</b>&nbsp;&nbsp;&nbsp;[<a href='".api_get_self()."?uInfo=".$user_id."&view=".Security::remove_XSS($new_view)."'>".get_lang('Close')."</a>]&nbsp;&nbsp;&nbsp;[<a href='userLogCSV.php?".api_get_cidreq()."&uInfo=".Security::remove_XSS($_GET['uInfo'])."&view=10000'>".get_lang('ExportAsCSV')."</a>]
  5477. </td>
  5478. </tr>
  5479. ";
  5480. echo "<tr><td style='padding-left : 40px;' valign='top'>".get_lang('LoginsDetails')."<br>";
  5481. $sql = "SELECT UNIX_TIMESTAMP(access_date), count(access_date)
  5482. FROM $track_access_table
  5483. WHERE access_user_id = '$user_id'
  5484. AND access_cours_code = '$course_id'
  5485. AND access_session_id = '$session_id'
  5486. GROUP BY YEAR(access_date),MONTH(access_date)
  5487. ORDER BY YEAR(access_date),MONTH(access_date) ASC";
  5488. echo "<tr><td style='padding-left : 40px;padding-right : 40px;'>";
  5489. //$results = getManyResults2Col($sql);
  5490. $results = getManyResults3Col($sql);
  5491. echo "<table cellpadding='2' cellspacing='1' border='0' align=center>";
  5492. echo "<tr>
  5493. <td class='secLine'>
  5494. ".get_lang('LoginsTitleMonthColumn')."
  5495. </td>
  5496. <td class='secLine'>
  5497. ".get_lang('LoginsTitleCountColumn')."
  5498. </td>
  5499. </tr>";
  5500. $total = 0;
  5501. if (is_array($results)) {
  5502. for($j = 0 ; $j < count($results) ; $j++) {
  5503. echo "<tr>";
  5504. echo "<td class='content'><a href='logins_details.php?uInfo=".$user_id."&reqdate=".$results[$j][0]."&view=".Security::remove_XSS($view)."'>".$MonthsLong[date('n', $results[$j][0])-1].' '.date('Y', $results[$j][0])."</a></td>";
  5505. echo "<td valign='top' align='right' class='content'>".$results[$j][1]."</td>";
  5506. echo"</tr>";
  5507. $total = $total + $results[$j][1];
  5508. }
  5509. echo "<tr>";
  5510. echo "<td>".get_lang('Total')."</td>";
  5511. echo "<td align='right' class='content'>".$total."</td>";
  5512. echo"</tr>";
  5513. } else {
  5514. echo "<tr>";
  5515. echo "<td colspan='2'><center>".get_lang('NoResult')."</center></td>";
  5516. echo"</tr>";
  5517. }
  5518. echo "</table>";
  5519. echo "</td></tr>";
  5520. } else {
  5521. $new_view = substr_replace($view,'1',0,1);
  5522. echo "
  5523. <tr>
  5524. <td valign='top'>
  5525. +<font color='#0000FF'>&nbsp;&nbsp;</font><a href='".api_get_self()."?uInfo=".$user_id."&view=".Security::remove_XSS($new_view)."' class='specialLink'>".get_lang('LoginsAndAccessTools')."</a>
  5526. </td>
  5527. </tr>
  5528. ";
  5529. }
  5530. }
  5531. /**
  5532. * Displays the exercise results for a specific user in a specific course.
  5533. * @todo remove globals
  5534. */
  5535. public function display_exercise_tracking_info($view, $user_id, $course_id)
  5536. {
  5537. global $TBL_TRACK_HOTPOTATOES, $TABLECOURSE_EXERCICES, $TABLETRACK_EXERCICES, $dateTimeFormatLong;
  5538. if(substr($view,1,1) == '1') {
  5539. $new_view = substr_replace($view,'0',1,1);
  5540. echo "<tr>
  5541. <td valign='top'>
  5542. <font color='#0000FF'>-&nbsp;&nbsp;&nbsp;</font><b>".get_lang('ExercicesResults')."</b>&nbsp;&nbsp;&nbsp;[<a href='".api_get_self()."?uInfo=".Security::remove_XSS($user_id)."&view=".Security::remove_XSS($new_view)."'>".get_lang('Close')."</a>]&nbsp;&nbsp;&nbsp;[<a href='userLogCSV.php?".api_get_cidreq()."&uInfo=".Security::remove_XSS($_GET['uInfo'])."&view=01000'>".get_lang('ExportAsCSV')."</a>]
  5543. </td>
  5544. </tr>";
  5545. echo "<tr><td style='padding-left : 40px;' valign='top'>".get_lang('ExercicesDetails')."<br />";
  5546. $sql = "SELECT ce.title, te.exe_result , te.exe_weighting, UNIX_TIMESTAMP(te.exe_date)
  5547. FROM $TABLECOURSE_EXERCICES AS ce , $TABLETRACK_EXERCICES AS te
  5548. WHERE te.exe_cours_id = '".Database::escape_string($course_id)."'
  5549. AND te.exe_user_id = '".intval($user_id)."'
  5550. AND te.exe_exo_id = ce.id
  5551. ORDER BY ce.title ASC, te.exe_date ASC";
  5552. $hpsql = "SELECT te.exe_name, te.exe_result , te.exe_weighting, UNIX_TIMESTAMP(te.exe_date)
  5553. FROM $TBL_TRACK_HOTPOTATOES AS te
  5554. WHERE te.exe_user_id = '".intval($user_id)."' AND te.exe_cours_id = '".Database::escape_string($course_id)."'
  5555. ORDER BY te.exe_cours_id ASC, te.exe_date ASC";
  5556. $hpresults = getManyResultsXCol($hpsql, 4);
  5557. $NoTestRes = 0;
  5558. $NoHPTestRes = 0;
  5559. echo "<tr>\n<td style='padding-left : 40px;padding-right : 40px;'>\n";
  5560. $results = getManyResultsXCol($sql, 4);
  5561. echo "<table cellpadding='2' cellspacing='1' border='0' align='center'>\n";
  5562. echo "
  5563. <tr bgcolor='#E6E6E6'>
  5564. <td>
  5565. ".get_lang('ExercicesTitleExerciceColumn')."
  5566. </td>
  5567. <td>
  5568. ".get_lang('Date')."
  5569. </td>
  5570. <td>
  5571. ".get_lang('ExercicesTitleScoreColumn')."
  5572. </td>
  5573. </tr>";
  5574. if (is_array($results)) {
  5575. for($i = 0; $i < sizeof($results); $i++) {
  5576. $display_date = api_convert_and_format_date($results[$i][3], null, date_default_timezone_get());
  5577. echo "<tr>\n";
  5578. echo "<td class='content'>".$results[$i][0]."</td>\n";
  5579. echo "<td class='content'>".$display_date."</td>\n";
  5580. echo "<td valign='top' align='right' class='content'>".$results[$i][1]." / ".$results[$i][2]."</td>\n";
  5581. echo "</tr>\n";
  5582. }
  5583. } else {
  5584. // istvan begin
  5585. $NoTestRes = 1;
  5586. }
  5587. // The Result of Tests
  5588. if(is_array($hpresults)) {
  5589. for($i = 0; $i < sizeof($hpresults); $i++) {
  5590. $title = GetQuizName($hpresults[$i][0],'');
  5591. if ($title == '')
  5592. $title = basename($hpresults[$i][0]);
  5593. $display_date = api_convert_and_format_date($hpresults[$i][3], null, date_default_timezone_get());
  5594. ?>
  5595. <tr>
  5596. <td class="content"><?php echo $title; ?></td>
  5597. <td class="content" align="center"><?php echo $display_date; ?></td>
  5598. <td class="content" align="center"><?php echo $hpresults[$i][1]; ?> / <?php echo $hpresults[$i][2]; ?>
  5599. </td>
  5600. </tr>
  5601. <?php }
  5602. } else {
  5603. $NoHPTestRes = 1;
  5604. }
  5605. if ($NoTestRes == 1 && $NoHPTestRes == 1) {
  5606. echo "<tr>\n";
  5607. echo "<td colspan='3'><center>".get_lang('NoResult')."</center></td>\n";
  5608. echo "</tr>\n";
  5609. }
  5610. echo "</table>";
  5611. echo "</td>\n</tr>\n";
  5612. } else {
  5613. $new_view = substr_replace($view,'1',1,1);
  5614. echo "
  5615. <tr>
  5616. <td valign='top'>
  5617. +<font color='#0000FF'>&nbsp;&nbsp;</font><a href='".api_get_self()."?uInfo=$user_id&view=".$new_view."' class='specialLink'>".get_lang('ExercicesResults')."</a>
  5618. </td>
  5619. </tr>";
  5620. }
  5621. }
  5622. /**
  5623. * Displays the student publications for a specific user in a specific course.
  5624. * @todo remove globals
  5625. */
  5626. public function display_student_publications_tracking_info($view, $user_id, $course_id)
  5627. {
  5628. global $TABLETRACK_UPLOADS, $TABLECOURSE_WORK, $dateTimeFormatLong, $_course;
  5629. if (substr($view,2,1) == '1') {
  5630. $new_view = substr_replace($view,'0',2,1);
  5631. echo "<tr>
  5632. <td valign='top'>
  5633. <font color='#0000FF'>-&nbsp;&nbsp;&nbsp;</font><b>".get_lang('WorkUploads')."</b>&nbsp;&nbsp;&nbsp;[<a href='".api_get_self()."?uInfo=".Security::remove_XSS($user_id)."&view=".Security::remove_XSS($new_view)."'>".get_lang('Close')."</a>]&nbsp;&nbsp;&nbsp;[<a href='userLogCSV.php?".api_get_cidreq()."&uInfo=".Security::remove_XSS($_GET['uInfo'])."&view=00100'>".get_lang('ExportAsCSV')."</a>]
  5634. </td>
  5635. </tr>";
  5636. echo "<tr><td style='padding-left : 40px;' valign='top'>".get_lang('WorksDetails')."<br>";
  5637. $sql = "SELECT u.upload_date, w.title, w.author,w.url
  5638. FROM $TABLETRACK_UPLOADS u , $TABLECOURSE_WORK w
  5639. WHERE u.upload_work_id = w.id
  5640. AND u.upload_user_id = '".intval($user_id)."'
  5641. AND u.upload_cours_id = '".Database::escape_string($course_id)."'
  5642. ORDER BY u.upload_date DESC";
  5643. echo "<tr><td style='padding-left : 40px;padding-right : 40px;'>";
  5644. $results = getManyResultsXCol($sql,4);
  5645. echo "<table cellpadding='2' cellspacing='1' border='0' align=center>";
  5646. echo "<tr>
  5647. <td class='secLine' width='40%'>
  5648. ".get_lang('WorkTitle')."
  5649. </td>
  5650. <td class='secLine' width='30%'>
  5651. ".get_lang('WorkAuthors')."
  5652. </td>
  5653. <td class='secLine' width='30%'>
  5654. ".get_lang('Date')."
  5655. </td>
  5656. </tr>";
  5657. if (is_array($results)) {
  5658. for($j = 0 ; $j < count($results) ; $j++) {
  5659. $pathToFile = api_get_path(WEB_COURSE_PATH).$_course['path']."/".$results[$j][3];
  5660. $beautifulDate = api_convert_and_format_date($results[$j][0], null, date_default_timezone_get());
  5661. echo "<tr>";
  5662. echo "<td class='content'>"
  5663. ."<a href ='".$pathToFile."'>".$results[$j][1]."</a>"
  5664. ."</td>";
  5665. echo "<td class='content'>".$results[$j][2]."</td>";
  5666. echo "<td class='content'>".$beautifulDate."</td>";
  5667. echo"</tr>";
  5668. }
  5669. } else {
  5670. echo "<tr>";
  5671. echo "<td colspan='3'><center>".get_lang('NoResult')."</center></td>";
  5672. echo"</tr>";
  5673. }
  5674. echo "</table>";
  5675. echo "</td></tr>";
  5676. } else {
  5677. $new_view = substr_replace($view,'1',2,1);
  5678. echo "
  5679. <tr>
  5680. <td valign='top'>
  5681. +<font color='#0000FF'>&nbsp;&nbsp;</font><a href='".api_get_self()."?uInfo=".Security::remove_XSS($user_id)."&view=".Security::remove_XSS($new_view)."' class='specialLink'>".get_lang('WorkUploads')."</a>
  5682. </td>
  5683. </tr>
  5684. ";
  5685. }
  5686. }
  5687. /**
  5688. * Displays the links followed for a specific user in a specific course.
  5689. * @todo remove globals
  5690. */
  5691. public function display_links_tracking_info($view, $user_id, $course_id)
  5692. {
  5693. global $TABLETRACK_LINKS, $TABLECOURSE_LINKS;
  5694. if (substr($view,3,1) == '1') {
  5695. $new_view = substr_replace($view,'0',3,1);
  5696. echo "
  5697. <tr>
  5698. <td valign='top'>
  5699. <font color='#0000FF'>-&nbsp;&nbsp;&nbsp;</font><b>".get_lang('LinksAccess')."</b>&nbsp;&nbsp;&nbsp;[<a href='".api_get_self()."?uInfo=".Security::remove_XSS($user_id)."&view=".Security::remove_XSS($new_view)."'>".get_lang('Close')."</a>]&nbsp;&nbsp;&nbsp;[<a href='userLogCSV.php?".api_get_cidreq()."&uInfo=".Security::remove_XSS($_GET['uInfo'])."&view=00010'>".get_lang('ExportAsCSV')."</a>]
  5700. </td>
  5701. </tr>
  5702. ";
  5703. echo "<tr><td style='padding-left : 40px;' valign='top'>".get_lang('LinksDetails')."<br>";
  5704. $sql = "SELECT cl.title, cl.url
  5705. FROM $TABLETRACK_LINKS AS sl, $TABLECOURSE_LINKS AS cl
  5706. WHERE sl.links_link_id = cl.id
  5707. AND sl.links_cours_id = '".Database::escape_string($course_id)."'
  5708. AND sl.links_user_id = '".intval($user_id)."'
  5709. GROUP BY cl.title, cl.url";
  5710. echo "<tr><td style='padding-left : 40px;padding-right : 40px;'>";
  5711. $results = getManyResults2Col($sql);
  5712. echo "<table cellpadding='2' cellspacing='1' border='0' align=center>";
  5713. echo "<tr>
  5714. <td class='secLine'>
  5715. ".get_lang('LinksTitleLinkColumn')."
  5716. </td>
  5717. </tr>";
  5718. if (is_array($results)) {
  5719. for($j = 0 ; $j < count($results) ; $j++) {
  5720. echo "<tr>";
  5721. echo "<td class='content'><a href='".$results[$j][1]."'>".$results[$j][0]."</a></td>";
  5722. echo"</tr>";
  5723. }
  5724. } else {
  5725. echo "<tr>";
  5726. echo "<td ><center>".get_lang('NoResult')."</center></td>";
  5727. echo"</tr>";
  5728. }
  5729. echo "</table>";
  5730. echo "</td></tr>";
  5731. } else {
  5732. $new_view = substr_replace($view,'1',3,1);
  5733. echo "
  5734. <tr>
  5735. <td valign='top'>
  5736. +<font color='#0000FF'>&nbsp;&nbsp;</font><a href='".api_get_self()."?uInfo=".Security::remove_XSS($user_id)."&view=".Security::remove_XSS($new_view)."' class='specialLink'>".get_lang('LinksAccess')."</a>
  5737. </td>
  5738. </tr>
  5739. ";
  5740. }
  5741. }
  5742. /**
  5743. * Displays the documents downloaded for a specific user in a specific course.
  5744. * @param string kind of view inside tracking info
  5745. * @param int User id
  5746. * @param string Course code
  5747. * @param int Session id (optional, default = 0)
  5748. * @return void
  5749. */
  5750. public static function display_document_tracking_info($view, $user_id, $course_id, $session_id = 0) {
  5751. // protect data
  5752. $user_id = intval($user_id);
  5753. $course_id = Database::escape_string($course_id);
  5754. $session_id = intval($session_id);
  5755. $downloads_table = Database::get_statistic_table(TABLE_STATISTIC_TRACK_E_DOWNLOADS);
  5756. if(substr($view,4,1) == '1') {
  5757. $new_view = substr_replace($view,'0',4,1);
  5758. echo "
  5759. <tr>
  5760. <td valign='top'>
  5761. <font color='#0000FF'>-&nbsp;&nbsp;&nbsp;</font><b>".get_lang('DocumentsAccess')."</b>&nbsp;&nbsp;&nbsp;[<a href='".api_get_self()."?uInfo=".Security::remove_XSS($user_id)."&view=".Security::remove_XSS($new_view)."'>".get_lang('Close')."</a>]&nbsp;&nbsp;&nbsp;[<a href='userLogCSV.php?".api_get_cidreq()."&uInfo=".Security::remove_XSS($_GET['uInfo'])."&view=00001'>".get_lang('ExportAsCSV')."</a>]
  5762. </td>
  5763. </tr>
  5764. ";
  5765. echo "<tr><td style='padding-left : 40px;' valign='top'>".get_lang('DocumentsDetails')."<br>";
  5766. $sql = "SELECT down_doc_path
  5767. FROM $downloads_table
  5768. WHERE down_cours_id = '".$course_id."'
  5769. AND down_user_id = '$user_id'
  5770. AND down_session_id = '$session_id'
  5771. GROUP BY down_doc_path";
  5772. echo "<tr><td style='padding-left : 40px;padding-right : 40px;'>";
  5773. $results = getManyResults1Col($sql);
  5774. echo "<table cellpadding='2' cellspacing='1' border='0' align='center'>";
  5775. echo "<tr>
  5776. <td class='secLine'>
  5777. ".get_lang('DocumentsTitleDocumentColumn')."
  5778. </td>
  5779. </tr>";
  5780. if (is_array($results)) {
  5781. for($j = 0 ; $j < count($results) ; $j++) {
  5782. echo "<tr>";
  5783. echo "<td class='content'>".$results[$j]."</td>";
  5784. echo"</tr>";
  5785. }
  5786. } else {
  5787. echo "<tr>";
  5788. echo "<td><center>".get_lang('NoResult')."</center></td>";
  5789. echo"</tr>";
  5790. }
  5791. echo "</table>";
  5792. echo "</td></tr>";
  5793. } else {
  5794. $new_view = substr_replace($view,'1',4,1);
  5795. echo "
  5796. <tr>
  5797. <td valign='top'>
  5798. +<font color='#0000FF'>&nbsp;&nbsp;</font><a href='".api_get_self()."?uInfo=".Security::remove_XSS($user_id)."&view=".Security::remove_XSS($new_view)."' class='specialLink'>".get_lang('DocumentsAccess')."</a>
  5799. </td>
  5800. </tr>
  5801. ";
  5802. }
  5803. }
  5804. /**
  5805. * Gets the IP of a given user, using the last login before the given date
  5806. * @param int User ID
  5807. * @param string Datetime
  5808. * @param bool Whether to return the IP as a link or just as an IP
  5809. * @param string If defined and return_as_link if true, will be used as the text to be shown as the link
  5810. * @return string IP address (or false on error)
  5811. * @assert (0,0) === false
  5812. */
  5813. public static function get_ip_from_user_event($user_id, $event_date, $return_as_link = false, $body_replace = null) {
  5814. if (empty($user_id) or empty($event_date)) {
  5815. return false;
  5816. }
  5817. $table_login = Database :: get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
  5818. $sql_ip = "SELECT login_date, login_ip FROM $table_login WHERE login_user_id = $user_id AND login_date < '$event_date' ORDER BY login_date DESC LIMIT 1";
  5819. $ip = '';
  5820. $res_ip = Database::query($sql_ip);
  5821. if ($res_ip !== false && Database::num_rows($res_ip)>0) {
  5822. $row_ip = Database::fetch_row($res_ip);
  5823. if ($return_as_link) {
  5824. $ip = Display::url((empty($body_replace)?$row_ip[1]:$body_replace), 'http://www.whatsmyip.org/ip-geo-location/?ip='.$row_ip[1], array('title'=>get_lang('TraceIP'), 'target'=>'_blank'));
  5825. } else {
  5826. $ip = $row_ip[1];
  5827. }
  5828. }
  5829. return $ip;
  5830. }
  5831. }
  5832. /**
  5833. * @package chamilo.tracking
  5834. */
  5835. class TrackingUserLogCSV
  5836. {
  5837. /**
  5838. * Displays the number of logins every month for a specific user in a specific course.
  5839. */
  5840. public function display_login_tracking_info($view, $user_id, $course_id, $session_id = 0)
  5841. {
  5842. $MonthsLong = $GLOBALS['MonthsLong'];
  5843. $track_access_table = Database::get_statistic_table(TABLE_STATISTIC_TRACK_E_ACCESS);
  5844. // protected data
  5845. $user_id = intval($user_id);
  5846. $session_id = intval($session_id);
  5847. $course_id = Database::escape_string($course_id);
  5848. $tempView = $view;
  5849. if(substr($view,0,1) == '1')
  5850. {
  5851. $new_view = substr_replace($view,'0',0,1);
  5852. $title[1]= get_lang('LoginsAndAccessTools').get_lang('LoginsDetails');
  5853. $sql = "SELECT UNIX_TIMESTAMP(access_date), count(access_date)
  5854. FROM $track_access_table
  5855. WHERE access_user_id = '$user_id'
  5856. AND access_cours_code = '".$course_id."'
  5857. AND access_session_id = '$session_id'
  5858. GROUP BY YEAR(access_date),MONTH(access_date)
  5859. ORDER BY YEAR(access_date),MONTH(access_date) ASC";
  5860. //$results = getManyResults2Col($sql);
  5861. $results = getManyResults3Col($sql);
  5862. $title_line= get_lang('LoginsTitleMonthColumn').';'.get_lang('LoginsTitleCountColumn')."\n";
  5863. $line='';
  5864. $total = 0;
  5865. if (is_array($results)) {
  5866. for($j = 0 ; $j < count($results) ; $j++) {
  5867. $line .= $results[$j][0].';'.$results[$j][1]."\n";
  5868. $total = $total + $results[$j][1];
  5869. }
  5870. $line .= get_lang('Total').";".$total."\n";
  5871. } else {
  5872. $line= get_lang('NoResult')."</center></td>";
  5873. }
  5874. } else {
  5875. $new_view = substr_replace($view,'1',0,1);
  5876. }
  5877. return array($title_line, $line);
  5878. }
  5879. /**
  5880. * Displays the exercise results for a specific user in a specific course.
  5881. * @todo remove globals
  5882. */
  5883. public function display_exercise_tracking_info($view, $user_id, $course_id)
  5884. {
  5885. global $TABLECOURSE_EXERCICES, $TABLETRACK_EXERCICES, $TABLETRACK_HOTPOTATOES, $dateTimeFormatLong;
  5886. if (substr($view,1,1) == '1') {
  5887. $new_view = substr_replace($view,'0',1,1);
  5888. $title[1]= get_lang('ExercicesDetails');
  5889. $line='';
  5890. $sql = "SELECT ce.title, te.exe_result , te.exe_weighting, UNIX_TIMESTAMP(te.exe_date)
  5891. FROM $TABLECOURSE_EXERCICES AS ce , $TABLETRACK_EXERCICES AS te
  5892. WHERE te.exe_cours_id = '$course_id'
  5893. AND te.exe_user_id = '$user_id'
  5894. AND te.exe_exo_id = ce.id
  5895. ORDER BY ce.title ASC, te.exe_date ASC";
  5896. $hpsql = "SELECT te.exe_name, te.exe_result , te.exe_weighting, UNIX_TIMESTAMP(te.exe_date)
  5897. FROM $TABLETRACK_HOTPOTATOES AS te
  5898. WHERE te.exe_user_id = '$user_id' AND te.exe_cours_id = '$course_id'
  5899. ORDER BY te.exe_cours_id ASC, te.exe_date ASC";
  5900. $hpresults = getManyResultsXCol($hpsql, 4);
  5901. $NoTestRes = 0;
  5902. $NoHPTestRes = 0;
  5903. $results = getManyResultsXCol($sql, 4);
  5904. $title_line=get_lang('ExercicesTitleExerciceColumn').";".get_lang('Date').';'.get_lang('ExercicesTitleScoreColumn')."\n";
  5905. if (is_array($results)) {
  5906. for($i = 0; $i < sizeof($results); $i++)
  5907. {
  5908. $display_date = api_convert_and_format_date($results[$i][3], null, date_default_timezone_get());
  5909. $line .= $results[$i][0].";".$display_date.";".$results[$i][1]." / ".$results[$i][2]."\n";
  5910. }
  5911. } else {
  5912. // istvan begin
  5913. $NoTestRes = 1;
  5914. }
  5915. // The Result of Tests
  5916. if (is_array($hpresults)) {
  5917. for($i = 0; $i < sizeof($hpresults); $i++) {
  5918. $title = GetQuizName($hpresults[$i][0],'');
  5919. if ($title == '')
  5920. $title = basename($hpresults[$i][0]);
  5921. $display_date = api_convert_and_format_date($hpresults[$i][3], null, date_default_timezone_get());
  5922. $line .= $title.';'.$display_date.';'.$hpresults[$i][1].'/'.$hpresults[$i][2]."\n";
  5923. }
  5924. } else {
  5925. $NoHPTestRes = 1;
  5926. }
  5927. if ($NoTestRes == 1 && $NoHPTestRes == 1) {
  5928. $line=get_lang('NoResult');
  5929. }
  5930. } else {
  5931. $new_view = substr_replace($view,'1',1,1);
  5932. }
  5933. return array($title_line, $line);
  5934. }
  5935. /**
  5936. * Displays the student publications for a specific user in a specific course.
  5937. * @todo remove globals
  5938. */
  5939. public function display_student_publications_tracking_info($view, $user_id, $course_id)
  5940. {
  5941. global $TABLETRACK_UPLOADS, $TABLECOURSE_WORK, $dateTimeFormatLong, $_course;
  5942. if (substr($view,2,1) == '1') {
  5943. $new_view = substr_replace($view,'0',2,1);
  5944. $sql = "SELECT u.upload_date, w.title, w.author, w.url
  5945. FROM $TABLETRACK_UPLOADS u , $TABLECOURSE_WORK w
  5946. WHERE u.upload_work_id = w.id
  5947. AND u.upload_user_id = '$user_id'
  5948. AND u.upload_cours_id = '$course_id'
  5949. ORDER BY u.upload_date DESC";
  5950. $results = getManyResultsXCol($sql,4);
  5951. $title[1]=get_lang('WorksDetails');
  5952. $line='';
  5953. $title_line=get_lang('WorkTitle').";".get_lang('WorkAuthors').";".get_lang('Date')."\n";
  5954. if (is_array($results)) {
  5955. for($j = 0 ; $j < count($results) ; $j++) {
  5956. $pathToFile = api_get_path(WEB_COURSE_PATH).$_course['path']."/".$results[$j][3];
  5957. $beautifulDate = api_convert_and_format_date($results[$j][0], null, date_default_timezone_get());
  5958. $line .= $results[$j][1].";".$results[$j][2].";".$beautifulDate."\n";
  5959. }
  5960. } else {
  5961. $line= get_lang('NoResult');
  5962. }
  5963. } else {
  5964. $new_view = substr_replace($view,'1',2,1);
  5965. }
  5966. return array($title_line, $line);
  5967. }
  5968. /**
  5969. * Displays the links followed for a specific user in a specific course.
  5970. * @todo remove globals
  5971. */
  5972. public function display_links_tracking_info($view, $user_id, $course_id)
  5973. {
  5974. global $TABLETRACK_LINKS, $TABLECOURSE_LINKS;
  5975. $line = null;
  5976. if (substr($view,3,1) == '1') {
  5977. $new_view = substr_replace($view,'0',3,1);
  5978. $title[1]=get_lang('LinksDetails');
  5979. $sql = "SELECT cl.title, cl.url
  5980. FROM $TABLETRACK_LINKS AS sl, $TABLECOURSE_LINKS AS cl
  5981. WHERE sl.links_link_id = cl.id
  5982. AND sl.links_cours_id = '$course_id'
  5983. AND sl.links_user_id = '$user_id'
  5984. GROUP BY cl.title, cl.url";
  5985. $results = getManyResults2Col($sql);
  5986. $title_line= get_lang('LinksTitleLinkColumn')."\n";
  5987. if (is_array($results)) {
  5988. for ($j = 0 ; $j < count($results) ; $j++) {
  5989. $line .= $results[$j][0]."\n";
  5990. }
  5991. } else {
  5992. $line=get_lang('NoResult');
  5993. }
  5994. } else {
  5995. $new_view = substr_replace($view,'1',3,1);
  5996. }
  5997. return array($title_line, $line);
  5998. }
  5999. /**
  6000. * Displays the documents downloaded for a specific user in a specific course.
  6001. * @param string kind of view inside tracking info
  6002. * @param int User id
  6003. * @param string Course code
  6004. * @param int Session id (optional, default = 0)
  6005. * @return void
  6006. */
  6007. public function display_document_tracking_info($view, $user_id, $course_id, $session_id = 0)
  6008. {
  6009. // protect data
  6010. $user_id = intval($user_id);
  6011. $course_id = Database::escape_string($course_id);
  6012. $session_id = intval($session_id);
  6013. $downloads_table = Database::get_statistic_table(TABLE_STATISTIC_TRACK_E_DOWNLOADS);
  6014. if (substr($view,4,1) == '1') {
  6015. $new_view = substr_replace($view,'0',4,1);
  6016. $title[1]= get_lang('DocumentsDetails');
  6017. $sql = "SELECT down_doc_path
  6018. FROM $downloads_table
  6019. WHERE down_cours_id = '$course_id'
  6020. AND down_user_id = '$user_id'
  6021. AND down_session_id = '$session_id'
  6022. GROUP BY down_doc_path";
  6023. $results = getManyResults1Col($sql);
  6024. $title_line = get_lang('DocumentsTitleDocumentColumn')."\n";
  6025. $line = null;
  6026. if (is_array($results)) {
  6027. for ($j = 0 ; $j < count($results) ; $j++) {
  6028. $line .= $results[$j]."\n";
  6029. }
  6030. } else {
  6031. $line = get_lang('NoResult');
  6032. }
  6033. } else {
  6034. $new_view = substr_replace($view,'1',4,1);
  6035. }
  6036. return array($title_line, $line);
  6037. }
  6038. /**
  6039. * @param $userId
  6040. * @param $courseInfo
  6041. * @param int $sessionId
  6042. * @return array
  6043. */
  6044. public static function getToolInformation(
  6045. $userId,
  6046. $courseInfo,
  6047. $sessionId = 0
  6048. ) {
  6049. $csvContent = array();
  6050. $courseToolInformation = null;
  6051. $headerTool = array(
  6052. array(get_lang('Title')),
  6053. array(get_lang('CreatedAt')),
  6054. array(get_lang('UpdatedAt')),
  6055. );
  6056. $headerListForCSV = array();
  6057. foreach ($headerTool as $item) {
  6058. $headerListForCSV[] = $item[0];
  6059. }
  6060. $courseForumInformationArray = getForumCreatedByUser(
  6061. $userId,
  6062. $courseInfo['real_id'],
  6063. $sessionId
  6064. );
  6065. if (!empty($courseForumInformationArray)) {
  6066. $csvContent[] = array();
  6067. $csvContent[] = get_lang('Forums');
  6068. $csvContent[] = $headerListForCSV;
  6069. foreach ($courseForumInformationArray as $row) {
  6070. $csvContent[] = $row;
  6071. }
  6072. $courseToolInformation .= Display::page_subheader2(
  6073. get_lang('Forums')
  6074. );
  6075. $courseToolInformation .= Display::return_sortable_table(
  6076. $headerTool,
  6077. $courseForumInformationArray
  6078. );
  6079. }
  6080. $courseWorkInformationArray = getWorkCreatedByUser(
  6081. $userId,
  6082. $courseInfo['real_id'],
  6083. $sessionId
  6084. );
  6085. if (!empty($courseWorkInformationArray)) {
  6086. $csvContent[] = null;
  6087. $csvContent[] = get_lang('Works');
  6088. $csvContent[] = $headerListForCSV;
  6089. foreach ($courseWorkInformationArray as $row) {
  6090. $csvContent[] = $row;
  6091. }
  6092. $csvContent[] = null;
  6093. $courseToolInformation .= Display::page_subheader2(
  6094. get_lang('Works')
  6095. );
  6096. $courseToolInformation .= Display::return_sortable_table(
  6097. $headerTool,
  6098. $courseWorkInformationArray
  6099. );
  6100. }
  6101. $courseToolInformationTotal = null;
  6102. if (!empty($courseToolInformation)) {
  6103. $sessionTitle = null;
  6104. if (!empty($sessionId)) {
  6105. $sessionTitle = ' ('.api_get_session_name($sessionId).')';
  6106. }
  6107. $courseToolInformationTotal .= Display::page_subheader(
  6108. $courseInfo['title'].$sessionTitle
  6109. );
  6110. $courseToolInformationTotal .= $courseToolInformation;
  6111. }
  6112. return array(
  6113. 'array' => $csvContent,
  6114. 'html' => $courseToolInformationTotal
  6115. );
  6116. }
  6117. }