Skip to content

Instantly share code, notes, and snippets.

@axiixc
Created April 20, 2012 01:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save axiixc/2425195 to your computer and use it in GitHub Desktop.
Save axiixc/2425195 to your computer and use it in GitHub Desktop.
Send assignments to the PLC grading server. Only tested for students.
#!/bin/bash
echo "Zipping assignment..."
zip assignment.zip file1.ss file2.ss file3.ss main.ss >> /dev/null
if [ $? -eq 0 ]
then
plcsend --send-file assignment.zip -user YOUR_USERNAME -pass YOUR_PASSWORD -id ASSIGNMENT_ID
else
echo "Error creating zip"
fi
#!/usr/bin/ruby
require 'rubygems'
require 'net/https'
require 'net/http/post/multipart' # sudo gem install multipart-post
require 'nokogiri' # sudo gem install nokogiri
require 'base64'
class PLCServerSession
API_BASE = 'https://plc.csse.rose-hulman.edu/'
API_NODES = {
# user[username] = [string:student_username]
# user[password] = [string:student_password]
:authenticate => {
:path => 'user/login_submit',
:method => :post
},
# List results of selected assignment
# Can also be used to change selected assignment
# Optionl: as_id = [int]
:assignments => {
:path => 'student/assignment',
:method => :get
},
# Submit an assignment
# submission[assignment_id] = [int]
# submission[submitted_file] = [file]
# submission[users] = [string:usernames]
:assignment_submit => {
:path => 'student/assignment_submit',
:method => :post_multipart
}
}
def send_file(path, id)
if !File.exists?(path)
puts "File not found: #{path}"
exit 1
end
puts "Sending assignment..."
response = nil
File.open(path) do |file|
response = make_api_request(:assignment_submit, {
"submission[assignment_id]" => id,
"submission[submitted_file]" => UploadIO.new(file, nil, path),
"submission[users]" => ""
})
end
if response.kind_of? Net::HTTPFound
puts "Graded! #{response['Location']}"
else
puts "Error grading"
end
end
def list_assignments
response = make_api_request(:assignments)
assignments = parse_assignments(response.body)
puts "+------------------------+"
puts "| ID | Name |"
puts "+------------------------+"
assignments.each do |assignment|
puts "| %-4d | %-15s |" % [ assignment[:id], assignment[:name] ]
end
puts "+------------------------+"
end
FMT_ASSIGNMENTS = "//li[contains(@class, 'tab')]//a"
def parse_assignments(html)
nodes = Nokogiri::HTML(html).xpath(FMT_ASSIGNMENTS).to_ary
nodes.map do |node|
{
:name => node.inner_text.strip,
:path => node['href'],
:id => node['href'].split('=')[1]
}
end
end
def authenticate_user(username, password)
response = make_api_request(:authenticate, {
"user[username]" => username,
"user[password]" => password
})
if response.kind_of? Net::HTTPFound
cookie = response['Set-Cookie']
marshal = Base64.decode64(cookie.split('; ')[0].split('=')[1])
@authentication_cookie = cookie if marshal.match(/failed!/).nil?
end
authenticated?
end
def authenticated?
!(@authentication_cookie.nil?)
end
def make_api_request(path, args = nil)
node = API_NODES[path]
url = URI.parse(API_BASE + node[:path])
request = nil
case node[:method]
when :get
request = Net::HTTP::Get.new url.path
request.set_form_data(args) unless args.nil?
when :post
request = Net::HTTP::Post.new url.path
request.set_form_data(args) unless args.nil?
when :post_multipart
request = Net::HTTP::Post::Multipart.new url.path, args
end
request['Cookie'] = @authentication_cookie if authenticated?
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
http.request(request)
end
end
class ArgumentParser
def initialize(args)
@arguments = {}
next_key = nil
args.each do |arg|
if next_key.nil?
case (arg = arg[1..-1])
when '-send-file'
enforce_single_action_constraint
@arguments[:action] = :send_file
next_key = :file_path
when '-list-assignments'
enforce_single_action_constraint
@arguments[:action] = :list_assignments
when 'user', 'pass', 'id'
next_key = arg.to_sym
else
puts "Error: Invalid argument"
print_help
end
else
@arguments[next_key] = arg
next_key = nil
end
end
if @arguments[:action].nil?
puts "Error: no action specified"
print_help
end
if @arguments[:action] == :send_file && @arguments[:file_path].nil?
puts "Error: missing file path"
print_help
end
if @arguments[:action] == :send_file && @arguments[:id].nil?
puts "Error: missing assignment id"
print_help
end
if @arguments[:user].nil? || @arguments[:pass].nil?
puts "Error: missing username or password"
print_help
end
end
def [](value)
@arguments[value]
end
def enforce_single_action_constraint
if !@arguments[:action].nil?
puts "Error: #{arguments[:action]} already set as action"
print_help
end
end
def print_help
puts <<-text
Usage: plcsend --send-file <file-path> -id <assignment-id>
plcsend --list-assignments
All request also require authentication via the following flags.
-user [string]
Specifies the username to use for authentication.
-pass [string]
Specifies the password to use for authentication.
text
exit 1
end
end
### ###
### main() ###
### ###
args = ArgumentParser.new(ARGV)
session = PLCServerSession.new
if !session.authenticate_user(args[:user], args[:pass])
puts "Authentication failed!"
exit 1
end
case args[:action]
when :send_file
session.send_file args[:file_path], args[:id]
when :list_assignments
session.list_assignments
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment