Commit 937d9318 authored by Zac Wood's avatar Zac Wood

Added Schedules endpoint that returns a plaintext iCal file.

Changed front end from downloading an iCal file to opening a webcal://

this was much less work than I expected
parent 4aaceed0
// Place all the behaviors and hooks related to the matching controller here.
// All this logic will automatically be available in application.js.
// Place all the styles related to the CalendarGenerator controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here:
require 'icalendar'
require 'time'
# Contains functionality for generating schedules.
class SchedulesController < ApplicationController
# Render an iCal file containing the schedules of all the
# course sections with the given CRNs.
def index
crns = params["crns"].split ','
@schedule = crns
render plain: @schedule.to_ical # render a plaintext iCal file
require 'icalendar'
require 'time'
# Contains functionality for generating schedules.
class CalendarGeneratorController < ApplicationController
# Render an iCal file containing the schedules of all the
# course sections with the given CRNs.
def new
cal =
# the intended format for the json is a list of CRNs
params[:_json].each do |crn| # for each CRN sent by the post request
section = CourseSection.find_by_crn(crn)
class Schedule
def initialize(crns)
@cal =
@cal.x_wr_calname = 'GMU Fall 2018'
@course_sections = do |crn|
CourseSection.find_by crn: crn
def to_ical
def load_events
@course_sections.each do |section|
unless section.start_time == "TBA" || section.end_time == "TBA"
event = generate_event_from_section(section)
if section.days.start_with? "M"
col_day_makeup = generate_event_after_columbus_day(section)
render plain: cal.to_ical # render a plaintext iCal file
# Configures a calendar event from a given section
# @param section [CourseSection]
def generate_event_from_section(section)
<p>Find me in app/views/calendar_generator/generate.html.erb</p>
......@@ -3,8 +3,7 @@ Rails.application.routes.draw do
scope :api do # Register /api routes
resources :courses, only: [:index, :show]
resources :course_sections, only: [:index]
post 'generate', controller: 'calendar_generator', action: 'new'
resources :schedules, only: [:index]
root 'courses#index' # Set the root to be the courses API endpoint
require 'test_helper'
class CalendarGeneratorControllerTest < ActionDispatch::IntegrationTest
test "should get generate" do
class SchedulesControllertest < ActionDispatch::IntegrationTest
test "should generate schedule" do
crns = [course_sections(:cs112001).crn, course_sections(:cs112002).crn]
post "/api/generate", params: crns.to_json, headers: { 'CONTENT_TYPE' => 'application/json' }
get "/api/schedules?crns=#{crns.join(',')}"
# DTSTAMP and UID lines uniquely identify events, so we can't test against them.
# so remove all the lines starting with them.
......@@ -9,10 +9,9 @@ interface ScheduleRootProps {
removeCourseSection: (courseSection: CourseSection) => any;
const generateSchedule = async (schedule: CourseSection[]): Promise<void> => {
const generateSchedule = async (schedule: CourseSection[]) => {
const crns = => section.crn);
const calendar = await ApiService.generateCalendar(crns);
downloadFile(calendar, 'GMU Fall 2018.ics');
const ScheduleRoot = ({ schedule, removeCourseSection }: ScheduleRootProps) => (
......@@ -7,8 +7,8 @@ class ApiService {
searchCourseSections = async (crn: string): Promise<any[]> =>
generateCalendar = async (crns: string[]): Promise<string> =>
postJson(`${this.apiRoot}/generate`, crns).then(response => response.text());
subscribeToCalendar = (crns: string[]) =>`webcal://localhost:3000/api/schedules?crns=${crns.join(',')}`, '_self');
const fetchJson = async (url: string): Promise<any> => fetch(url).then(response => response.json());
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment