Permalink
Browse files

First draft for lichen plagiarism detector (#2239)

* create run-plagiarism-detector form

* create run-plagiarism-detector form2

* create run-plagiarism-detector form 3

* convert plagiarism form to page

* store plagiarism form value in json that will be used by cronjob to run plagiarism

* add code boxes to display plagiarism result

* render user 1 code for plagiarism in code box 1

* resolve registration section sorting for numeric and checkpoint gradeable

* render matching user 2 code in code box 2

* modified plagiarism form

* modified plagiarism form 2

* lichen , lichen/config, lichen/provided_code dir will be created at time of sample course creation

* lichen , lichen/config, lichen/provided_code dir will be created at time of new course creation

* moved displayCode function to server side

* better error message when ajax call breaks and further modifications

* add color to code box 1

* add color feature for code boxes

* add toggle feature

* migrator for creating lichen directories

* don't crash if file does not exist

* some minor wording

* use new migration arguments
  • Loading branch information...
tushargr authored and bmcutler committed Jun 29, 2018
1 parent 3080ffb commit 2b6d91b0ac34df21d2991cb935656c90bb5cd9d7
@@ -758,6 +758,7 @@ def create(self):
# On python 3, replace with os.makedirs(..., exist_ok=True)
os.system("mkdir -p {}".format(os.path.join(course_path, "submissions")))
os.system('chown hwphp:{}_tas_www {}'.format(self.code, os.path.join(course_path, 'submissions')))

for gradeable in self.gradeables:
#create_teams
json_team_history = {}
@@ -0,0 +1,31 @@
import os
import grp

def up(conn, semester, course):

course_dir = os.path.join("/var/local/submitty/courses",semester,course)
lichen_dir = os.path.join(course_dir,"lichen")
lichen_config_dir = os.path.join(lichen_dir,"config")
lichen_provided_dir = os.path.join(lichen_dir,"provided_code")

# create the directories
os.makedirs(lichen_dir, exist_ok=True)
os.makedirs(lichen_config_dir, exist_ok=True)
os.makedirs(lichen_provided_dir, exist_ok=True)

# get course group
stat_info = os.stat(course_dir)
course_group_id = stat_info.st_gid
course_group = grp.getgrgid(course_group_id)[0]

# set the owner/group/permissions
os.system("chown -R hwphp:"+course_group+" "+lichen_dir)
os.system("chmod -R u+rwx "+lichen_dir)
os.system("chmod -R g+rwxs "+lichen_dir)
os.system("chmod -R o-rwx "+lichen_dir)

pass


def down(conn, semester, course):
pass
@@ -222,6 +222,9 @@ create_and_set u=rwx,g=rwxs,o= $instructor $ta_www_group $course_dir/custo
# drwxr-s--- $HWCRON_USER ta_www_group uploads/
# drwxr-s--- $HWPHP_USER ta_www_group uploads/bulk_pdf/
# drwxr-s--- $HWCGI_USER ta_www_group uploads/split_pdf/
# drwxr-s--- $HWCRON_USER ta_www_group lichen/
# drwxr-s--- $HWPHP_USER ta_www_group lichen/config
# drwxr-s--- $HWPHP_USER ta_www_group lichen/provided_code
create_and_set u=rwx,g=rxs,o= $HWPHP_USER $ta_www_group $course_dir/submissions
create_and_set u=rwx,g=rxs,o= $HWPHP_USER $ta_www_group $course_dir/forum_attachments
create_and_set u=rwx,g=rxs,o= $HWPHP_USER $ta_www_group $course_dir/config_upload
@@ -230,6 +233,9 @@ create_and_set u=rwx,g=rxs,o= $HWCRON_USER $ta_www_group $course_dir/
create_and_set u=rwx,g=rxs,o= $HWCRON_USER $ta_www_group $course_dir/uploads
create_and_set u=rwx,g=rxs,o= $HWPHP_USER $ta_www_group $course_dir/uploads/bulk_pdf
create_and_set u=rwx,g=rxs,o= $HWCGI_USER $ta_www_group $course_dir/uploads/split_pdf
create_and_set u=rwx,g=rxs,o= $HWCRON_USER $ta_www_group $course_dir/lichen
create_and_set u=rwx,g=rwxs,o= $HWPHP_USER $ta_www_group $course_dir/lichen/config
create_and_set u=rwx,g=rwxs,o= $HWPHP_USER $ta_www_group $course_dir/lichen/provided_code


# NOTE: instructor uploads TA HW grade reports & overall grade scores here

Large diffs are not rendered by default.

Oops, something went wrong.
@@ -395,8 +395,56 @@ public static function getContentType($filename){
break;
default:
$content_type = 'text/x-sh';
break;
break;$gradeable_ids = array_diff(scandir("/var/local/submitty/courses/$semester/$course/submissions/"), array('.', '..'));
}
return $content_type;
}
/**
* This function returns a array consisting of all semesters, and within each semester, there will be courses for that semester, and
* within each course , there will be list of all gradeable ids for that course
* @return array $return
*/
public static function getGradeablesFromPriorTerm(){
$return = array();
$filename = "/var/local/submitty/courses/gradeables_from_prior_terms.txt";
if (file_exists($filename)) {
$file = fopen($filename, "r") or exit("Unable to open file!");
while(!feof($file)){
$line = fgets($file);
$line= trim($line," ");
$line= explode("/",$line);
$sem = $line[5];
$course = $line[6];
$gradeables= array();
while(!feof($file)){
$line = fgets($file);
if(trim(trim($line," "),"\n") == "") {
break;
}
array_push($gradeables, trim(trim($line," "),"\n"));
}
$return[$sem][$course] = $gradeables;
}
fclose($file);
uksort($return, function($semester_a, $semester_b) {
$year_a = (int)substr($semester_a, 1);
$year_b = (int)substr($semester_b, 1);
if($year_a > $year_b)
return 0;
else if ($year_a < $year_b)
return 1;
else {
return ($semester_a[0] == 'f')? 0 : 1 ;
}
});
}
return $return;
}
}
@@ -58,7 +58,7 @@ public function header($breadcrumbs, $css=array(), $js=array()) {
];
$navURLs[] = [
"href" => $this->core->buildUrl(array('component' => 'admin', 'page' => 'plagiarism')),
"title" => "Plagiarism Detection"
"title" => "Lichen Plagiarism Detection [WIP]"
];
}
}
@@ -28,7 +28,7 @@ public function plagiarismIndex($semester, $course, $assignment) {
$return = "";
$return .= <<<HTML
<div class="content">
<h1 class="centered">Plagiarism Detection - $assignment</h1>
<h1 class="centered">Lichen Plagiarism Detection - $assignment</h1>
<br>
HTML;
$return .= file_get_contents("/var/local/submitty/courses/$semester/$course/plagiarism/report/var/local/submitty/courses/$semester/$course/submissions/$assignment/index.html");
@@ -38,27 +38,228 @@ public function plagiarismIndex($semester, $course, $assignment) {
return $return;
}
public function plagiarismTree($semester, $course, $assignments) {
public function plagiarismTree($semester, $course, $assignments, $gradeable_ids_titles) {
$return = "";
$return .= <<<HTML
<div class="content">
<h1 style="text-align: center">Plagiarism Detection</h1>
<h1 style="text-align: center">Lichen Plagiarism Detection -- WORK IN PROGRESS</h1>
<br>
HTML;
if ($assignments) {
$return .= '<ul>';
foreach ($assignments as $assignment) {
$return .= "<li><a href=\"{$this->core->buildUrl(array('component' => 'admin', 'page' => 'plagiarism', 'action' => 'index', 'assignment' => $assignment))}\">$assignment</a></li>";
}
$return .= '</ul>';
} else {
$return .= <<<HTML
<div class="nav-buttons">
<a class="btn btn-primary" href="{$this->core->buildUrl(array('component' => 'admin', 'page' => 'plagiarism', 'action' => 'plagiarism_form'))}">Configure Lichen Plagiarism Detection</a>
</div><br /><br /><br />
<form id="gradeables_with_plagiarism_result">
Gradeables with Plagiarism Result:
<select name="gradeable_id">
<option value="" selected>None</option>
HTML;
foreach ($gradeable_ids_titles as $gradeable_id_title) {
$title = $gradeable_id_title['g_title'];
$id = $gradeable_id_title['g_id'];
$return .= <<<HTML
<p>It looks like you have yet to run plagiarism detection on any assignment. See <a href="http://submitty.org/instructor/plagiarism">http://submitty.org/instructor/plagiarism</a> for details.</p>
<option value="{$id}">$title</option>
HTML;
}
$return .= <<<HTML
</select>
</form><br /><br />
<div class="sub">
<form id="users_with_plagiarism">
User 1 (sorted by %match):
<select name="user_id_1">
<option value="">None</option>
</select>
Version:
<select name="version_user_1">
<option value="">None</option>
</select>
<span style="float:right;"> User 2:
<select name="user_id_2">
<option value="">None</option>
</select>
<a name="toggle" class="btn btn-primary" onclick="toggleUsersPlagiarism();">Toggle</a>
</span>
</form><br />
<div name="code_box_1" style="float:left;width:45%;height:500px;line-height:1.5em;overflow:scroll;padding:5px;border: solid 1px #555;background:white;border-width: 2px;">
</div>
<div name="code_box_2" style="float:right;width:45%;height:500px;line-height:1.5em;overflow:scroll;padding:5px;border: solid 1px #555;background:white;border-width: 2px;">
</div>
</div>
HTML;
$return .= <<<HTML
</div>
<script>
var form1 = $("#gradeables_with_plagiarism_result");
var form2 = $("#users_with_plagiarism");
$('[name="gradeable_id"]', form1).change(function(){
setRankingForGradeable();
});
$('[name="user_id_1"]', form2).change(function(){
setUserSubmittedCode('user_id_1');
});
$('[name="version_user_1"]', form2).change(function(){
setUserSubmittedCode('version_user_1');
});
$('[name="user_id_2"]', form2).change(function(){
setUserSubmittedCode('user_id_2');
});
</script>
HTML;
return $return;
}
public function plagiarismForm($gradeable_ids_titles, $prior_term_gradeables) {
$prior_term_gradeables_json = json_encode($prior_term_gradeables);
$semester = $this->core->getConfig()->getSemester();
$course = $this->core->getConfig()->getCourse();
$return = "";
$return .= <<<HTML
<div class="content">
<h1 style="text-align: center">Lichen Plagiarism Detection Configuration -- WORK IN PROGRESS</h1>
<br>
HTML;
$return .= <<<HTML
<div id="run-plagiarism-form" style="overflow:auto;">
<form method="post" action="{$this->core->buildUrl(array('component' => 'admin', 'page' => 'plagiarism', 'course' => $course, 'semester' => $semester, 'action' => 'run_plagiarism'))}" enctype="multipart/form-data">
<input type="hidden" name="csrf_token" value="{$this->core->getCsrfToken()}" />
<input type="hidden" name="prior_term_gradeables_number" value="1" />
<input type="hidden" name="ignore_submission_number" value="1" /><br />
<div style="width:100%;">
<div style="width:20%;float:left">Select Gradeable:</div>
<div style="width:70%;float:right">
<select name="gradeable_id">
HTML;
foreach ($gradeable_ids_titles as $gradeable_id_title) {
$title = $gradeable_id_title['g_title'];
$id = $gradeable_id_title['g_id'];
$return .= <<<HTML
<option value="{$id}">$title</option>
HTML;
}
$return .= <<<HTML
</select>
</div>
</div><br /><br /><br /><br /><br />
<div style="width:100%;">
<div style="width:20%;float:left">Instructor Provided Code:</div>
<div style="width:70%;float:right">
<input type="radio" id="no_code_provided_id" value="no_code_provided" name="provided_code_option" checked >
<label for="no_code_provided_id">No</label>
<input type="radio" id="code_provided_id" value="code_provided" name="provided_code_option" >
<label for="code_provided_id">Yes</label><br />
<input type="file" name="provided_code_file">
</div>
</div><br /><br /><br /><br /><br />
<div style="width:100%;">
<div style="width:20%;float:left">Version:</div>
<div style="width:70%;float:right">
<input type="radio" id="all_version_id" value="all_version" name="version_option" checked >
<label for="all_version_id">All Version</label>
<input type="radio" id="active_version_id" value="active_version" name="version_option" >
<label for="active_version_id">Only Active Version</label><br />
</div>
</div><br /><br /><br /><br /><br />
<div style="width:100%;">
<div style="width:20%;float:left">Files to be Compared:</div>
<div style="width:70%;float:right">
<input type="radio" id="all_files_id" value="all_files" name="file_option" checked>
<label for="all_files_id">All Files</label>
<input type="radio" id="regrex_matching_files_id" value="regrex_matching_files" name="file_option" >
<label for="regrex_matching_files_id">Regrex matching files</label><br />
<input type="text" name="regrex_to_select_files" />
</div>
</div><br /><br /><br /><br /><br />
<div style="width:100%;">
<div style="width:20%;float:left">Language:</div>
<div style="width:70%;float:right">
<select name="language">
<option value="python">Python</option>
<option value="cpp">C++</option>
<option value="java">Java</option>
<option value="plaintext">Plain Text</option>
</select>
</div>
</div><br /><br /><br /><br /><br />
<div style="width:100%;">
<div style="width:20%;float:left">Threshold to be considered as Plagiarism:</div>
<div style="width:70%;float:right">
<input type="text" name="threshold"/ value="5" />
</div>
</div><br /><br /><br /><br /><br />
<div style="width:100%;">
<div style="width:20%;float:left">Sequence Length:</div>
<div style="width:70%;float:right">
<input type="text" name="sequence_length" value="10"/>
</div>
</div><br /><br /><br /><br /><br />
<div style="width:100%;overflow:auto;">
<div style="width:20%;float:left">Prior Terms Gradeables:</div>
<div style="width:70%;float:right;overflow:auto;" name= "prev_gradeable_div">
<select name="prev_sem_0">
<option value="">None</option>
HTML;
foreach ($prior_term_gradeables as $sem => $sem_gradeables) {
$return .= <<<HTML
<option value="{$sem}">$sem</option>
HTML;
}
$return .= <<<HTML
</select>
<select name="prev_course_0">
<option value="">None</option>
</select>
<select name="prev_gradeable_0">
<option value="">None</option>
</select>
</div><br />
<div style="width:70%;float:right">
<span name="add_more_prev_gradeable">
<i class="fa fa-plus-square" aria-hidden="true" ></i>Add more
</span>
</div>
</div><br /><br /><br /><br /><br />
<div style="width:100%;overflow:auto;">
<div style="width:20%;float:left">Are there any submissions that should be ignored?</div>
<div name="ignore_submission_div" style="width:70%;float:right;overflow:auto;">
<input type="radio" id="ignore_none_id" value="no_ignore" name="ignore_submission_option" checked >
<label for="ignore_none_id">No</label>
<input type="radio" id="ignore_id" value="ignore" name="ignore_submission_option" >
<label for="ignore_id">Yes</label><br />
<input type="text" name="ignore_submission_0" />
</div><br />
<div style="width:70%;float:right">
<span name="add_more_ignore">
<i class="fa fa-plus-square" aria-hidden="true" ></i>Add more
</span>
</div>
</div><br /><br />
<div style="float: right; width: auto; margin-top: 5px;">
<a href="{$this->core->buildUrl(array('component' => 'admin', 'page' => 'plagiarism', 'course' => $course, 'semester' => $semester))}" class="btn btn-danger">Cancel</a>
<input class="btn btn-primary" type="submit" value="Save Configuration" />
</div><br /><br /><br />
</form>
</div>
</div>
<script>
var form = $("#run-plagiarism-form");
var prior_term_gradeables = JSON.parse('{$prior_term_gradeables_json}');
$("select").change(function(){
var select_element_name = $(this).attr("name");
PlagiarismFormOptionChanged(prior_term_gradeables, select_element_name);
});
$('[name="add_more_prev_gradeable"]', form).on('click', function(){
addMorePriorTermGradeable(prior_term_gradeables);
});
$('[name="add_more_ignore"]', form).on('click', function(){
var ignore_submission_number = $('[name="ignore_submission_number"]', form).val();
$('[name="ignore_submission_div"]', form).append('<br /><input type="text" name="ignore_submission_'+ ignore_submission_number +'" />');
$('[name="ignore_submission_number"]', form).val(parseInt(ignore_submission_number)+1);
});
</script>
HTML;
return $return;
}
}
Oops, something went wrong.

0 comments on commit 2b6d91b

Please sign in to comment.