Subversion Repositories wimsdev

Rev

Rev 3718 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. /*    Copyright (C) 1998-2003 XIAO, Gang of Universite de Nice - Sophia Antipolis
  2.  *
  3.  *  This program is free software; you can redistribute it and/or modify
  4.  *  it under the terms of the GNU General Public License as published by
  5.  *  the Free Software Foundation; either version 2 of the License, or
  6.  *  (at your option) any later version.
  7.  *
  8.  *  This program is distributed in the hope that it will be useful,
  9.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11.  *  GNU General Public License for more details.
  12.  *
  13.  *  You should have received a copy of the GNU General Public License
  14.  *  along with this program; if not, write to the Free Software
  15.  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16.  */
  17.  
  18.         /* Routines treating user scores. */
  19.  
  20. double oldfactor=0.85;  /* quality factor, should remain stable. */
  21.  
  22. enum{ sr_require, sr_weight, sr_score, sr_mean, sr_remain};
  23. char scorebuf[MAX_CLASSEXOS*sizeof(scoreresult)+32];
  24. struct scoreresult *rscore;
  25. int scorecnt;
  26. double scoresum[MAX_SHEETS];
  27. int sheetstart[MAX_SHEETS], shexocnt[MAX_SHEETS];
  28. int examstart, examcnt;
  29. char rscore_class[MAX_CLASSLEN+1];
  30. char rscore_user[MAX_NAMELEN+1];
  31.  
  32. int totsheets=0;
  33. int score_ispublic=0;
  34. int score_status=-1;            /* save of score status */
  35. int score_statussheet=-1;
  36. int score_statusisexam=-1;
  37. double scorerecfactor=0.9;
  38.  
  39.         /* gather user score, core routine. */
  40. int getscoreuser(char *classe, char *user)
  41. {
  42.     int i, j, osh, sh;
  43.     double s;
  44.     char *nowuser, *nowsheet, *nowexo, *nowscore;
  45.     char *pp;
  46.     if(*user==0) {
  47.         user=getvar("wims_user");
  48.         if(user==NULL || *user==0) return -1;
  49.     }
  50.     if(strcmp(classe,rscore_class)==0 && strcmp(user,rscore_user)==0) return 0;
  51.     nowsheet=nowexo=nowscore="";
  52.     nowuser=getvar("wims_user"); if(nowuser!=NULL && strcmp(user,nowuser)==0) {
  53.         nowscore=getvar("module_score"); if(nowscore!=NULL && *nowscore!=0) {
  54.             nowsheet=getvar("wims_sheet"); if(nowsheet==NULL) nowsheet="";
  55.             nowexo=getvar("wims_exo"); if(nowexo==NULL) nowexo="";
  56.         }
  57.         else nowscore="";
  58.     }
  59.     snprintf(scorebuf+sizeof(int),sizeof(scorebuf)-sizeof(int),
  60.              "-c%s -u%s getscore %s %s %s",
  61.              classe,user,nowsheet,nowexo,nowscore);
  62.     i=kerneld(scorebuf,sizeof(scorebuf)); if(i<0)
  63.       internal_error("getscoreuser(): daemon failure.");
  64.     if(memcmp(scorebuf+sizeof(int),"OK",2)!=0) {
  65.         if(memcmp(scorebuf+sizeof(int),"ERROR",5)==0) {
  66.             module_error(find_word_start(scorebuf+sizeof(int)+8));
  67.         }
  68.         else internal_error("getscoreuser(): communication error with wimslogd.");
  69.     }
  70.     pp=scorebuf+sizeof(int)+3; rscore=(struct scoreresult *) pp;
  71.     scorecnt=(i-sizeof(int)-3)/sizeof(scoreresult);
  72.     if(scorecnt>MAX_CLASSEXOS) module_error("too_many_exercises");
  73.     s=0; for(i=osh=0;i<scorecnt;i++) {
  74.         sh=(rscore[i].num>>8)+1;
  75.         if(sh<1 || sh>MAX_SHEETS) break;
  76.         if(osh>0 && osh<sh) {scoresum[osh-1]=s; s=0;}
  77.         for(;osh<sh && osh<MAX_SHEETS;osh++) sheetstart[osh]=i;
  78.         s+=rscore[i].require*rscore[i].weight;
  79.     }
  80.     if(osh>0) scoresum[osh-1]=s; totsheets=osh;
  81.     for(j=0;j<totsheets-1;j++) shexocnt[j]=sheetstart[j+1]-sheetstart[j];
  82.     shexocnt[totsheets-1]=i-sheetstart[totsheets-1];
  83.     examstart=i; examcnt=scorecnt-examstart;
  84.     mystrncpy(rscore_class,classe,sizeof(rscore_class));
  85.     mystrncpy(rscore_user,user,sizeof(rscore_user));
  86.     return 0;
  87. }
  88.  
  89. char *scorepname[]={
  90.      "class","user","sheet","work","exam"
  91. };
  92. #define scorepname_no (sizeof(scorepname)/sizeof(scorepname[0]))
  93. char score_class[MAX_CLASSLEN+1];
  94. int score_sheet,score_exo,score_isexam;
  95. char score_user[256];
  96.  
  97.         /* Uniformed treatment of score command parameters
  98.          * format: class=? user=? sheet=? work=?
  99.          * all are optional. */
  100. void _scoreparm(char *p)
  101. {
  102.     int i;
  103.     char *pn, *pe, *pd, *pf;
  104.     char sav;
  105.    
  106.     score_sheet=score_exo=score_isexam=score_ispublic=0; *score_class=0;
  107.     score_user[0]=0;
  108.     for(i=0;i<scorepname_no;i++) {
  109.         pf=p;
  110.         ahead:
  111.         pn=strstr(pf,scorepname[i]); pf=pn+1;
  112.         if(pn==NULL) continue;
  113.         if(pn>p && !isspace(*(pn-1))) goto ahead;
  114.         pe=find_word_start(pn+strlen(scorepname[i]));
  115.         if(*pe!='=') goto ahead;
  116.         pd=find_word_start(pe+1);
  117.         pf=find_word_end(pd);
  118.         if(pf<=pd) continue;
  119.         sav=*pf; *pf=0;
  120.         switch(i) {
  121.             case 0: /* class */
  122.               mystrncpy(score_class,pd,sizeof(score_class)); break;
  123.             case 1: /* user */
  124.               mystrncpy(score_user,pd,sizeof(score_user)); break;
  125.             case 2: { /* sheet */
  126.                 if(*pd=='P') {pd++; score_ispublic=1;}
  127.                 score_sheet=atoi(pd);
  128.                 break;
  129.             }
  130.             case 3: /* work */
  131.               score_exo=atoi(pd); break;
  132.             case 4: /* exam */
  133.               score_isexam=1; break;
  134.         }
  135.         *pf=sav; strcpy(pn, pf);
  136.     }
  137.     *p=0;
  138.     if((*score_class!=0 || score_user[0]!=0) && !trusted_module()) {
  139.         module_error("not_trusted"); return;
  140.     }
  141.     if(*score_class==0) {
  142.         char *classe;
  143.         classe=getvar("wims_class");
  144.         if(classe==NULL || *classe==0) return;
  145.         else mystrncpy(score_class,classe,sizeof(score_class));
  146.     }
  147.     if(score_user[0]==0) {
  148.         char *user;
  149.         user=getvar("wims_user");
  150.         if(user!=NULL) mystrncpy(score_user,user,sizeof(score_user));
  151.     }
  152. }
  153.  
  154.         /* gather user score. */
  155. void _getscore(char *p,int dtype)
  156. {
  157.     int i,sh,ex,osh;
  158.     float d;
  159.     char *p1;
  160.  
  161.     _scoreparm(p);
  162.     if(score_class==0 || *score_user==0) return;
  163.     if(getscoreuser(score_class,score_user)<0) return;
  164.     for(i=osh=0,p1=p;i<scorecnt && p1-p<MAX_LINELEN-32;i++) {
  165.         sh=(rscore[i].num>>8)+1; if(sh<1 || sh>MAX_SHEETS) break;
  166.         if(score_sheet!=0) {
  167.             if(sh<score_sheet) continue;
  168.             if(sh>score_sheet || sh>MAX_SHEETS) break;
  169.         }
  170.         ex=((rscore[i].num)&255)+1;
  171.         if(score_exo!=0 && ex!=score_exo) continue;
  172.         if(osh!=0 && sh!=osh) *p1++='\n';
  173.         switch(dtype) {
  174.             case sr_require: {d=rscore[i].require; break;}
  175.             case sr_weight: {d=rscore[i].weight; break;}
  176.             case sr_score: {d=rscore[i].score; break;}
  177.             case sr_mean: {d=rscore[i].mean; break;}
  178.             case sr_remain: {d=rscore[i].require-rscore[i].score; break;}
  179.             default: {d=0; break;}
  180.         }
  181.         p1=moneyprint(p1,d); *p1++=' ';
  182.         osh=sh;
  183.     }
  184.     *p1++='\n'; *p1=0;
  185. }
  186.  
  187.         /* gather user score. */
  188. void calc_getscore(char *p)
  189. {
  190.     _getscore(p,sr_score);
  191. }
  192.  
  193.         /* gather user score average. */
  194. void calc_getscoremean(char *p)
  195. {
  196.     _getscore(p,sr_mean);
  197. }
  198.  
  199.         /* gather remaining of score to get for user. */
  200. void calc_getscoreremain(char *p)
  201. {
  202.     _getscore(p,sr_remain);
  203. }
  204.  
  205.         /* Require score table. */
  206. void calc_getscorerequire(char *p)
  207. {
  208.     _getscore(p,sr_require);
  209. }
  210.  
  211.         /* Score weight table. */
  212. void calc_getscoreweight(char *p)
  213. {
  214.     _getscore(p,sr_weight);
  215. }
  216.  
  217.         /* percentage of work done for each sheet. */
  218. void calc_getscorepercent(char *p)
  219. {
  220.     int i,j,jend;
  221.     double tot, mean, d;
  222.     char *p1;
  223.  
  224.     _scoreparm(p);
  225.     if(score_class==0 || *score_user==0) return;
  226.     if(getscoreuser(score_class,score_user)<0) return;
  227.     for(p1=p,i=0;i<totsheets && p1-p<MAX_LINELEN-32;i++) {
  228.         if(scoresum[i]==0) {
  229.             strcpy(p1,"0 0\n"); p1+=strlen(p1); continue;
  230.         }
  231.         if(score_sheet!=0 && i!=score_sheet-1) continue;
  232.         if(scoresum[i]<=0) *p1++='\n';
  233.         tot=mean=0; jend=sheetstart[i]+shexocnt[i];
  234.         for(j=sheetstart[i];j<jend;j++) {
  235.                 /* if mean<1 then ignore score.
  236.                  * if mean<2 then half score. */
  237.             if(rscore[j].mean>=1) {
  238.                 double dt=rscore[j].score;
  239.                 if(rscore[j].mean<2) dt=dt/2;
  240.                 d=dt*rscore[j].weight;
  241.                 mean+=rscore[j].mean*d; tot+=d;
  242.             }
  243.         }
  244.         if(tot>0) d=mean/tot; else d=0;
  245.         p1=moneyprint(p1,rint(100*tot/scoresum[i])); *p1++=' ';
  246.         p1=moneyprint(p1,d); *p1++='\n';
  247.     }
  248.     *p1=0;
  249. }
  250.  
  251.         /* Returns the status of a sheet, or -1 if error */
  252. int getsheetstatus(char *classe, int sheet)
  253. {
  254.     char *p, *st, buf[MAX_LINELEN+1], namebuf[MAX_FNAME+1];
  255.     int i;
  256.  
  257.     if(isexam || score_isexam) st="exam"; else st="sheet";
  258.     mkfname(namebuf,"%s/%s/%ss/.%ss",class_base,classe,st,st);
  259.     direct_datafile=1;datafile_fnd_record(namebuf,sheet,buf);direct_datafile=0;
  260.     p=find_word_start(buf); if(*p==0) return -1;
  261.     i=*p-'0'; if(i>5 || i<0) i=-1;
  262.     if((isexam || score_isexam) && i==0) {
  263.         p=getvar("wims_user"); if(p!=NULL && strcmp(p,"supervisor")==0) i=1;
  264.     }
  265.     return i;
  266. }
  267.  
  268.         /* return 1 if a word of bf2 is a substring of host.
  269.          * Content of bf2 is destroyed. */
  270. int _subword(char bf2[])
  271. {
  272.     char *p1, *p2;
  273.     for(p1=strchr(bf2,'\\'); p1!=NULL; p1=strchr(p1+1,'\\')) {
  274.         char buf[MAX_LINELEN+1], buf2[MAX_LINELEN+1], fbuf[MAX_FNAME+1];
  275.         char *classp, *classp2, *userp, *scp;
  276.         classp=getvar("wims_class"); userp=getvar("wims_user");
  277.         if(classp==NULL || userp==NULL || *classp==0 || *userp==0) break;
  278.         scp=getvar("wims_superclass");
  279.         if(scp!=NULL && *scp!=0) classp2=scp; else classp2=classp;
  280.         if(p1>bf2 && !isspace(*(p1-1))) continue;
  281.         if(!isalnum(*(p1+1))) continue;
  282.         p2=find_word_end(p1); if(p2>=p1+MAX_NAMELEN) continue;
  283.         memmove(buf2, p1+1, p2-p1-1); buf2[p2-p1-1]=0;
  284.         snprintf(buf,sizeof(buf),"user__%s",buf2);
  285.         if(strcmp(userp,"supervisor")==0)
  286.           mkfname(fbuf,"%s/%s/supervisor",class_base,classp);
  287.         else
  288.           mkfname(fbuf,"%s/%s/.users/%s",class_base,classp2,userp);
  289.         getdef(fbuf,buf,buf2); if(buf2[0]==0) strcpy(buf2,"none");
  290.         string_modify(bf2,p1,p2,buf2);
  291.         p1+=strlen(buf2);
  292.     }
  293.     if((isexam || score_isexam) && bf2[0]=='#') return 1;
  294.     if(wordchr(bf2,"none")!=NULL) return 0;
  295.     if(wordchr(bf2,"all")!=NULL) return 1;
  296.     p1=find_word_start(bf2); if(*p1==0) return 1;
  297.     return checkhostt(p1);
  298. }
  299.  
  300.         /* Returns 1 if score registration is open, 0 otherwise. */
  301. int _getscorestatus(char *classe, int sheet)
  302. {
  303.     char nbuf[MAX_LINELEN+1], gbuf[MAX_LINELEN+1];
  304.     char *es;
  305.  
  306.     if(classe==NULL || *classe==0 || sheet<=0) return 1;
  307.     if(getsheetstatus(classe,sheet)!=1) return 0;
  308.     if(*remote_addr==0) return 0;
  309.     if(isexam || score_isexam) {        /* exam simulation */
  310.         accessfile(nbuf,"r","%s/%s/.E%d",class_base,classe,sheet);
  311.         if(nbuf[0]=='#') return 1;
  312.     }
  313.         /* Global restriction data */
  314.     accessfile(nbuf,"r","%s/%s/.security",class_base,classe);
  315.     if(nbuf[0]) {
  316.         _getdef(nbuf,"allow",gbuf);
  317.         if(*find_word_start(gbuf)!=0 && _subword(gbuf)==0)
  318.           return 0;
  319.         _getdef(nbuf,"except",gbuf);
  320.         if(*find_word_start(gbuf)!=0 && _subword(gbuf)==1)
  321.           return 0;
  322.     }
  323.  
  324.         /* Sheet restriction data */
  325.     if(isexam || score_isexam) es="E"; else es="";
  326.     accessfile(nbuf,"r","%s/%s/.%s%d",class_base,classe,es,sheet);
  327.     if(*find_word_start(nbuf)==0) return 1;
  328.     return _subword(nbuf);
  329. }
  330.  
  331.         /* Returns 1 if score registration is open, 0 otherwise. */
  332. int getscorestatus(char *classe, int sheet)
  333. {
  334.     if(score_status<0 || score_statussheet!=sheet
  335.        || score_statusisexam!=isexam) {
  336.         score_statussheet=sheet; score_statusisexam=isexam;
  337.         score_status=_getscorestatus(classe,sheet); score_isexam=0;
  338.         if(score_status==1 && (cmd_type==cmd_new || cmd_type==cmd_renew
  339.                                || isexam)) {
  340.             char *p;
  341.             p=getvar("wims_scorereg");
  342.             if(p==NULL || strcmp(p,"suspend")!=0)
  343.               setvar("wims_scoring","pending");
  344.             else setvar("wims_scoring","");
  345.         }
  346.     }
  347.     if(isexam && score_status==0) {
  348.         char *p;
  349.         p=getvar("wims_user"); if(p==NULL || strcmp(p,"supervisor")!=0)
  350.           user_error("exam_closed");
  351.     }
  352.     return score_status;
  353. }
  354.  
  355.         /* Whether score registering is open */
  356. void calc_getscorestatus(char *p)
  357. {
  358.     _scoreparm(p);
  359.     if(score_class==0 || score_sheet==0 || *score_user==0) {
  360.         *p=0; return;
  361.     }
  362.     if(getscorestatus(score_class, score_sheet))
  363.       strcpy(p,"yes");
  364.     else strcpy(p,"no");
  365. }
  366.  
  367. double exam_scoredata[64];
  368.  
  369.         /* get current exam score */
  370. void exam_currscore(int esh)
  371. {
  372.     char *p, *bf, pb[MAX_FNAME+1];
  373.     char *s, *p1, *p2, *e1, *e2;
  374.     int i;
  375.    
  376.     for(i=0;i<MAX_EXOS;i++) exam_scoredata[i]=-1000;
  377.         /* session_prefix is not yet defined here */
  378.     s=getvar("wims_session"); if(s==NULL || *s==0) return;
  379.     mystrncpy(pb,s,sizeof(pb));
  380.     p=strchr(pb,'_'); if(p!=NULL) *p=0;
  381.     bf=readfile(mkfname(NULL,"%s/%s/examscore.%d",session_dir,pb,esh),NULL,WORKFILE_LIMIT);
  382.     if(bf==NULL) return;
  383.     for(p1=bf;*p1;p1=p2) {
  384.         p2=strchr(p1,'\n'); if(*p2) *p2++=0;
  385.         else p2=p1+strlen(p1);
  386.         p1=find_word_start(find_word_end(find_word_start(p1)));
  387.         e1=find_word_end(p1); if(*e1) *e1++=0;
  388.         e1=find_word_start(e1); e2=find_word_start(find_word_end(e1));
  389.         *find_word_end(e1)=0;
  390.         i=atoi(p1);
  391.         if(i>=1 && i<=MAX_EXOS &&
  392.            exam_scoredata[i-1]==-1000 && strcmp(e1,"score")==0) {
  393.             *find_word_end(e2)=0;
  394.             exam_scoredata[i-1]=atof(e2);
  395.         }
  396.     }
  397.     free(bf);
  398. }
  399.  
  400.         /* Gather exam score. */
  401. void calc_examscore(char *p)
  402. {
  403.     char *p1;
  404.     int i;
  405.    
  406.     _scoreparm(p); *p=0;
  407.     if(*score_class==0 || *score_user==0) return;
  408.     if(getscoreuser(score_class,score_user)<0) return;
  409.     p1=p;
  410.     for(i=0; i<examcnt && p1-p<MAX_LINELEN-32; i++) {
  411.         p1=moneyprint(p1,rscore[examstart+i].score); *p1++=' ';
  412.     }
  413.     *p1++='\n';
  414.     for(i=0; i<examcnt && p1-p<MAX_LINELEN-32; i++) {
  415.         p1=moneyprint(p1,rscore[examstart+i].require); *p1++=' ';
  416.         p1=moneyprint(p1,floor(rscore[examstart+i].mean/2)); *p1++=' ';
  417.         p1=moneyprint(p1,(int) rscore[examstart+i].mean%2); *p1++='\n';
  418.     }
  419.     *p1=0;
  420. }
  421.  
  422.         /* check score dependency.
  423.          * returns 1 if requirements are met. */
  424. int _depcheck(char *ds, struct scoreresult *rs, int ecnt)
  425. {
  426.     char *p1, *p2, *p3, *p4, *pp;
  427.     int perc, t, sum;
  428.     double tgot, ttot, tmean;
  429.    
  430.     for(p1=ds; *p1; p1=p3) {
  431.         p2=strchr(p1,':'); if(p2==NULL) break;
  432.         *p2++=0; p2=find_word_start(p2);
  433.         for(p3=p2; myisdigit(*p3); p3++);
  434.         if(p3<=p2) break;
  435.         *p3++=0; perc=atoi(p2);
  436.         if(perc<=0 || perc>100) break;
  437.         for(pp=p1; *pp; pp++) if(!myisdigit(*pp)) *pp=' ';
  438.         tgot=ttot=tmean=0; sum=0;
  439.         for(pp=find_word_start(p1); *pp; pp=find_word_start(p4)) {
  440.             p4=find_word_end(pp); if(*p4) *p4++=0;
  441.             t=atoi(pp); if(t<=0 || t>ecnt) goto lend;
  442.             t--;
  443.             ttot+=rs[t].require; tgot+=rs[t].score; tmean+=rs[t].mean;
  444.             sum++;
  445.         }
  446.         if(ttot<10) continue;
  447.         if(tgot/ttot*sqrt(tmean/(sum*10))*100<perc) {
  448.             for(pp=p1;pp<p2-1;pp++) if(!*pp) *pp=',';
  449.             *pp=0; setvar("dep_list",p1);
  450.             return 0;
  451.         }
  452.         lend: ;
  453.     }
  454.     return 1;
  455. }
  456.  
  457. int depcheck(char *sh, int exo, char *deps)
  458. {
  459.     char buf[MAX_LINELEN+1];
  460.     char *s, sbuf[64];
  461.     int i, is;
  462.    
  463.     s=getvar("wims_session");
  464.     if(s==NULL || *s==0 || strstr(s,"robot")!=NULL) return 0;
  465.     mystrncpy(sbuf,s,sizeof(sbuf));
  466.     s=strchr(sbuf,'_'); if(s) *s=0;
  467.     accessfile(buf,"r","../sessions/%s/exodep.%s",sbuf,sh);
  468.     if(buf[0]==0) {     /* no dep file found */
  469.         is=atoi(sh); if(is<=0 || is>totsheets) return 0;
  470.         s=getvar("wims_class"); if(s==NULL || *s==0) return 0;
  471.         getscoreuser(s,"");
  472.         return _depcheck(deps,rscore+sheetstart[is-1],shexocnt[is-1]);
  473.     }
  474.     for(i=1,s=strchr(buf,':'); s && i<exo; i++, s=strchr(s+1,':'));
  475.     if(s==NULL) return 0;       /* bad file or exo number */
  476.     if(myisdigit(*++s)) return 0; else return 1;
  477. }
  478.  
  479. int exam_depcheck(char *deps, int exam)
  480. {
  481.     struct scoreresult esc[MAX_EXOS];
  482.     int i;
  483.     exam_currscore(exam);
  484.     for(i=0;i<MAX_EXOS;i++) {
  485.         esc[i].require=esc[i].mean=10;
  486.         if(exam_scoredata[i]==-1000) esc[i].score=0;
  487.         else esc[i].score=exam_scoredata[i];
  488.     }
  489.     return _depcheck(deps,esc,MAX_EXOS);
  490. }
  491.  
  492.