diff --git a/vms/pom/pages/basePage.py b/vms/pom/pages/basePage.py index 6c01c11..c47782a 100644 --- a/vms/pom/pages/basePage.py +++ b/vms/pom/pages/basePage.py @@ -60,3 +60,4 @@ def execute_script(self, script, element): def remove_i18n(string): slashes = [pos for pos, char in enumerate(string) if char == '/'] return string[:slashes[2]] + string[slashes[3]:] + diff --git a/vms/pom/pages/completedShiftsPage.py b/vms/pom/pages/completedShiftsPage.py index f7cc304..9ee48b4 100644 --- a/vms/pom/pages/completedShiftsPage.py +++ b/vms/pom/pages/completedShiftsPage.py @@ -8,6 +8,7 @@ class CompletedShiftsPage(BasePage): view_hours_page = PageUrls.completed_shifts_page + live_server_url = '' def __init__(self, driver): self.driver = driver @@ -16,7 +17,8 @@ def __init__(self, driver): super(CompletedShiftsPage, self).__init__(driver) def go_to_completed_shifts(self): - self.home_page.get_completed_shifts_link().click() + link = self.home_page.get_completed_shifts_link().get_attribute('href') + self.get_page('', link) def edit_hours(self, stime, etime): self.element_by_xpath(self.elements.SHIFT_EDIT_PATH + '//a').click() diff --git a/vms/pom/pages/manageShiftPage.py b/vms/pom/pages/manageShiftPage.py index 1b31646..45364fe 100644 --- a/vms/pom/pages/manageShiftPage.py +++ b/vms/pom/pages/manageShiftPage.py @@ -10,6 +10,8 @@ class ManageShiftPage(BasePage): shift_page = PageUrls.manage_volunteer_shift_page shift_assignment_text = 'Assign Shift' + VIEW_SHIFT = 'View Shifts' + VIEW_JOB = 'View Jobs' no_volunteer_shift_message = 'This volunteer does not have any upcoming shifts.' live_server_url = '' diff --git a/vms/pom/pages/upcomingShiftsPage.py b/vms/pom/pages/upcomingShiftsPage.py index 2e68efb..412169a 100644 --- a/vms/pom/pages/upcomingShiftsPage.py +++ b/vms/pom/pages/upcomingShiftsPage.py @@ -10,6 +10,7 @@ class UpcomingShiftsPage(BasePage): view_shift_page = PageUrls.upcoming_shifts_page no_shift_message = 'You do not have any upcoming shifts.' + live_server_url = '' def __init__(self, driver): self.driver = driver @@ -19,7 +20,7 @@ def __init__(self, driver): super(UpcomingShiftsPage, self).__init__(driver) def view_upcoming_shifts(self): - self.home_page.get_upcoming_shifts_link().send_keys('\n') + self.home_page.get_upcoming_shifts_link().click() def submit_form(self): self.element_by_xpath(self.elements.SUBMIT_PATH).submit() diff --git a/vms/shift/tests/test_manageVolunteerShift.py b/vms/shift/tests/test_manageVolunteerShift.py index 189ffd3..11d402f 100644 --- a/vms/shift/tests/test_manageVolunteerShift.py +++ b/vms/shift/tests/test_manageVolunteerShift.py @@ -4,22 +4,21 @@ # third party from selenium import webdriver from selenium.common.exceptions import NoSuchElementException +from selenium.webdriver.support.ui import WebDriverWait +from selenium.webdriver.support import expected_conditions as EC +from selenium.webdriver.common.by import By # local Django from pom.pages.authenticationPage import AuthenticationPage from pom.pages.eventSignUpPage import EventSignUpPage from pom.pages.manageShiftPage import ManageShiftPage -from shift.models import VolunteerShift from shift.utils import (create_admin, create_volunteer_with_details, create_event_with_details, create_job_with_details, create_shift_with_details) -# Class contains failing test cases which have been documented -# Test class commented out to prevent travis build failure -""" class ManageVolunteerShift(LiveServerTestCase): - ''' + """ Admin users have ManageVolunteerShift View which has the following functionalities: - Filter Volunteers according to certain criteriras @@ -34,7 +33,7 @@ class ManageVolunteerShift(LiveServerTestCase): View of Admin Profile. Tests Included. - Test View with/without any registered volunteers - - Test Redirection to events view on clicking `Manage Shifts` + - Test Redirection to events view on clicking `Manage Shifts` - Test Jobs page without jobs - Test assign shifts without any registered shifts - Test assign shifts with registered shifts @@ -44,11 +43,15 @@ class ManageVolunteerShift(LiveServerTestCase): assigned shift - Test if a shift can be assigned to a volunteer who has already been assigned the same shift - ''' + """ @classmethod def setUpClass(cls): + """Method to initiate class level objects. + This method initiates Firefox WebDriver, WebDriverWait and + the corresponding POM objects for this Test Class + """ cls.volunteer_1 = [ 'volunteer-one', 'volunteer-one', 'volunteer-one', 'volunteer-one', 'volunteer-one', 'volunteer-one', 'volunteer-one', '9999999999', @@ -66,96 +69,154 @@ def setUpClass(cls): cls.sign_up_page = EventSignUpPage(cls.driver) cls.manage_shift_page = ManageShiftPage(cls.driver) cls.authentication_page = AuthenticationPage(cls.driver) + cls.wait = WebDriverWait(cls.driver, 10) super(ManageVolunteerShift, cls).setUpClass() def setUp(self): + """ + Method consists of statements to be executed before + start of each test. + """ create_admin() self.login_admin() def tearDown(self): - pass + """ + Method consists of statements to be executed at + end of each test. + """ + self.authentication_page.logout() @classmethod def tearDownClass(cls): + """ + Class method to quit the Firefox WebDriver session after + execution of all tests in class. + """ cls.driver.quit() super(ManageVolunteerShift, cls).tearDownClass() def login_admin(self): + """ + Utility function to login as administrator. + """ self.authentication_page.server_url = self.live_server_url self.authentication_page.login({ 'username': 'admin', 'password': 'admin' }) - def create_shift(self, shift): - # register event to create job - event = ['event-name', '2017-05-20', '2017-05-20'] + @staticmethod + def create_shift(shift): + """ + Utility function to create a valid shift. + :param shift: Iterable containing details of shift. + :return: Shift type object. + """ + # Register event to create job + event = ['event-name', '2050-05-20', '2050-05-20'] e1 = create_event_with_details(event) - # create job to create shift - job = ['job name', '2017-05-20', '2017-05-20', 'job description', e1] + # Create job to create shift + job = ['job name', '2050-05-20', '2050-05-20', 'job description', e1] j1 = create_job_with_details(job) - # create shift to assign - shift_1 = ['2017-05-20', shift[0], shift[1], shift[2], j1] + # Create shift to assign + shift_1 = ['2050-05-20', shift[0], shift[1], shift[2], j1] s1 = create_shift_with_details(shift_1) return s1 def check_job_details(self, details): + """ + Utility function to perform assertions on job details received as param. + :param details: Iterable consisting details of job to check. + """ sign_up_page = self.sign_up_page self.assertEqual(sign_up_page.get_shift_job(), details[0]) self.assertEqual(sign_up_page.get_shift_date(), details[1]) self.assertEqual(sign_up_page.get_shift_start_time(), details[2]) self.assertEqual(sign_up_page.get_shift_end_time(), details[3]) + def wait_for_home_page(self): + """ + Utility function to perform explicit wait for home page. + """ + self.wait.until( + EC.presence_of_element_located( + (By.XPATH, + "//h1[contains(text(), 'Volunteer Management System')]" + ) + ) + ) + def test_table_layout(self): + """ + Test the shift table has details displayed correctly. + """ sign_up_page = self.sign_up_page manage_shift_page = self.manage_shift_page + manage_shift_page.live_server_url = self.live_server_url - # register volunteers - v1 = create_volunteer_with_details(self.volunteer_1) + # Register volunteers + volunteer_1 = create_volunteer_with_details(self.volunteer_1) shift = ['09:00', '15:00', '1'] - s1 = self.create_shift(shift) + shift_1 = self.create_shift(shift) - self.manage_shift_page.live_server_url = self.live_server_url - # open manage volunteer shift + self.wait_for_home_page() + + # Open manage volunteer shift self.manage_shift_page.navigate_to_manage_shift_page() - # volunteer-one does not have any registered shifts + # Volunteer-one does not have any registered shifts manage_shift_page.select_volunteer(1) manage_shift_page.assign_shift() - # events shown in table - with self.assertRaises(NoSuchElementException): - sign_up_page.get_info_box() - self.assertEqual(sign_up_page.get_view_jobs(), 'View Jobs') + # Events shown in table + self.assertRaisesRegexp(NoSuchElementException, + 'Message: Unable to locate element: .alert-info', + sign_up_page.get_info_box) + self.assertEqual(sign_up_page.get_view_jobs(), + manage_shift_page.VIEW_JOB) sign_up_page.click_to_view_jobs() - # arrived on page2 with jobs - self.assertEqual(sign_up_page.get_view_shifts(), 'View Shifts') + # Arrived on page2 with jobs + self.assertEqual(sign_up_page.get_view_shifts(), + manage_shift_page.VIEW_SHIFT) sign_up_page.click_to_view_shifts() - # arrived on page3 with shifts, assign shift to volunteer one - self.assertEqual(sign_up_page.get_sign_up(), 'Assign Shift') + # Arrived on page3 with shifts, assign shift to volunteer one + self.assertEqual(sign_up_page.get_sign_up(), + manage_shift_page.shift_assignment_text) def test_landing_page_without_any_registered_volunteers(self): + """ + Test manage shifts page with no registered data. + """ manage_shift_page = self.manage_shift_page - self.manage_shift_page.live_server_url = self.live_server_url - # open manage volunteer shift - self.manage_shift_page.navigate_to_manage_shift_page() + manage_shift_page.live_server_url = self.live_server_url + + self.wait_for_home_page() + + # Open manage volunteer shift manage_shift_page.navigate_to_manage_shift_page() - with self.assertRaises(NoSuchElementException): - manage_shift_page.find_table_row() + self.assertRaisesRegexp(NoSuchElementException, + 'Message: Unable to locate element: tr', + manage_shift_page.find_table_row) def test_landing_page_with_registered_volunteers(self): + """ + Test details on manage shifts page with data registered. + """ manage_shift_page = self.manage_shift_page - self.manage_shift_page.live_server_url = self.live_server_url + manage_shift_page.live_server_url = self.live_server_url + + # Register volunteer + volunteer_1 = create_volunteer_with_details(self.volunteer_1) - # register volunteer - v1 = create_volunteer_with_details(self.volunteer_1) + self.wait_for_home_page() manage_shift_page.navigate_to_manage_shift_page() @@ -165,14 +226,20 @@ def test_landing_page_with_registered_volunteers(self): manage_shift_page.no_volunteer_shift_message) def test_events_page_with_no_events(self): + """ + Test no event present at shifts sign up page for volunteer to sign up for. + """ sign_up_page = self.sign_up_page manage_shift_page = self.manage_shift_page - # register volunteers - v1 = create_volunteer_with_details(self.volunteer_1) + # Register volunteers + volunteer_1 = create_volunteer_with_details(self.volunteer_1) - self.manage_shift_page.live_server_url = self.live_server_url - # open manage volunteer shift + manage_shift_page.live_server_url = self.live_server_url + + self.wait_for_home_page() + + # Open manage volunteer shift self.manage_shift_page.navigate_to_manage_shift_page() manage_shift_page.select_volunteer(1) @@ -182,18 +249,23 @@ def test_events_page_with_no_events(self): sign_up_page.no_event_message) def test_jobs_page_with_no_jobs(self): + """ + Test no job present at shifts sign up page for volunteer to sign up for. + """ sign_up_page = self.sign_up_page manage_shift_page = self.manage_shift_page - self.manage_shift_page.live_server_url = self.live_server_url + manage_shift_page.live_server_url = self.live_server_url - # register volunteers - v1 = create_volunteer_with_details(self.volunteer_1) + # Register volunteers + volunteer_1 = create_volunteer_with_details(self.volunteer_1) - # create events + # Create events event = ['event-name', '2017-05-20', '2017-05-20'] - e1 = create_event_with_details(event) + event_1 = create_event_with_details(event) - # open manage volunteer shift + self.wait_for_home_page() + + # Open manage volunteer shift manage_shift_page.navigate_to_manage_shift_page() manage_shift_page.select_volunteer(1) manage_shift_page.assign_shift() @@ -202,42 +274,52 @@ def test_jobs_page_with_no_jobs(self): sign_up_page.no_event_message) def test_assign_shifts_with_no_shifts(self): + """ + Test no shift present at shifts sign up page for volunteer to sign up for. + """ sign_up_page = self.sign_up_page manage_shift_page = self.manage_shift_page - self.manage_shift_page.live_server_url = self.live_server_url + manage_shift_page.live_server_url = self.live_server_url - # register volunteers - v1 = create_volunteer_with_details(self.volunteer_1) + # Register volunteers + volunteer_1 = create_volunteer_with_details(self.volunteer_1) - # create events + # Create events event = ['event-name', '2017-05-20', '2017-05-20'] - e1 = create_event_with_details(event) + event_1 = create_event_with_details(event) - # create jobs - job = ['job name', '2017-05-20', '2017-05-20', 'job description', e1] - j1 = create_job_with_details(job) + # Create jobs + job = ['job name', '2017-05-20', '2017-05-20', 'job description', event_1] + job_1 = create_job_with_details(job) - # open manage volunteer shift + self.wait_for_home_page() + + # Open manage volunteer shift manage_shift_page.navigate_to_manage_shift_page() manage_shift_page.select_volunteer(1) manage_shift_page.assign_shift() - # no events shown in table + # No events shown in table self.assertEqual(sign_up_page.get_info_box().text, sign_up_page.no_event_message) def test_assign_shifts_with_registered_shifts(self): + """ + Test assignment of shift present at shifts sign up page for volunteer to sign up for. + """ sign_up_page = self.sign_up_page manage_shift_page = self.manage_shift_page - self.manage_shift_page.live_server_url = self.live_server_url + manage_shift_page.live_server_url = self.live_server_url - # register volunteers - v1 = create_volunteer_with_details(self.volunteer_1) + # Register volunteers + volunteer_1 = create_volunteer_with_details(self.volunteer_1) shift = ['09:00', '15:00', '1'] - s1 = self.create_shift(shift) + shift_1 = self.create_shift(shift) - # volunteer-one does not have any registered shifts + self.wait_for_home_page() + + # Volunteer-one does not have any registered shifts manage_shift_page.navigate_to_manage_shift_page() manage_shift_page.select_volunteer(1) self.assertEqual(manage_shift_page.get_info_box(), @@ -245,127 +327,132 @@ def test_assign_shifts_with_registered_shifts(self): manage_shift_page.assign_shift() - # events shown in table - with self.assertRaises(NoSuchElementException): - sign_up_page.get_info_box() + # Events shown in table + self.assertRaisesRegexp(NoSuchElementException, + 'Unable to locate element: .alert-info', + sign_up_page.get_info_box) manage_shift_page.navigate_to_shift_assignment_page() - # confirm on shift assignment to volunteer-one + # Confirm on shift assignment to volunteer-one manage_shift_page.submit_form() - with self.assertRaises(NoSuchElementException): - sign_up_page.get_danger_box() + self.assertRaisesRegexp(NoSuchElementException, + 'Unable to locate element: .alert-danger', + sign_up_page.get_danger_box) - # check shift assignment to volunteer-one + # Check shift assignment to volunteer-one manage_shift_page.navigate_to_manage_shift_page() manage_shift_page.select_volunteer(1) self.check_job_details( - ['job name', 'May 20, 2017', '9 a.m.', '3 p.m.']) - - # database check to ensure volunteer has been assigned the shift - self.assertEqual(len(VolunteerShift.objects.all()), 1) - self.assertNotEqual( - len( - VolunteerShift.objects.filter( - volunteer_id=v1.id, shift_id=s1.id)), 0) + ['job name', 'May 20, 2050', '9 a.m.', '3 p.m.']) def test_slots_remaining_in_shift(self): + """ + Test correct display of the remaining number of slots for shift. + """ sign_up_page = self.sign_up_page manage_shift_page = self.manage_shift_page - self.manage_shift_page.live_server_url = self.live_server_url + manage_shift_page.live_server_url = self.live_server_url - # register volunteers - v1 = create_volunteer_with_details(self.volunteer_1) - v2 = create_volunteer_with_details(self.volunteer_2) + # Register volunteers + volunteer_1 = create_volunteer_with_details(self.volunteer_1) + volunteer_2 = create_volunteer_with_details(self.volunteer_2) shift = ['09:00', '15:00', '1'] - s1 = self.create_shift(shift) + shift_1 = self.create_shift(shift) - # open manage volunteer shift + # Open manage volunteer shift manage_shift_page.navigate_to_manage_shift_page() - # volunteer-one does not have any registered shifts + # Volunteer-one does not have any registered shifts manage_shift_page.select_volunteer(1) self.assertEqual(manage_shift_page.get_info_box(), manage_shift_page.no_volunteer_shift_message) manage_shift_page.assign_shift() - # events shown in table - with self.assertRaises(NoSuchElementException): - sign_up_page.get_info_box() + # Events shown in table + self.assertRaisesRegexp(NoSuchElementException, + 'Unable to locate element: .alert-info', + sign_up_page.get_info_box) manage_shift_page.navigate_to_shift_assignment_page() - # confirm on shift assignment to volunteer-one + # Confirm on shift assignment to volunteer-one manage_shift_page.submit_form() - with self.assertRaises(NoSuchElementException): - sign_up_page.get_danger_box() + self.assertRaisesRegexp(NoSuchElementException, + 'Unable to locate element: .alert-danger', + sign_up_page.get_danger_box) - # check shift assignment to volunteer-one + # Check shift assignment to volunteer-one manage_shift_page.navigate_to_manage_shift_page() manage_shift_page.select_volunteer(1) self.check_job_details( - ['job name', 'May 20, 2017', '9 a.m.', '3 p.m.']) + ['job name', 'May 20, 2050', '9 a.m.', '3 p.m.']) - # open manage volunteer shift again to assign shift to volunteer two + # Open manage volunteer shift again to assign shift to volunteer two manage_shift_page.navigate_to_manage_shift_page() - # volunteer-two does not have any registered shifts + # Volunteer-two does not have any registered shifts manage_shift_page.select_volunteer(2) self.assertEqual(manage_shift_page.get_info_box(), manage_shift_page.no_volunteer_shift_message) manage_shift_page.assign_shift() - # no events shown in table + # No events shown in table self.assertEqual(sign_up_page.get_info_box().text, sign_up_page.no_event_message) def test_cancel_assigned_shift(self): + """ + Test successful cancellation of shift. + """ sign_up_page = self.sign_up_page manage_shift_page = self.manage_shift_page self.manage_shift_page.live_server_url = self.live_server_url - # register volunteers - v1 = create_volunteer_with_details(self.volunteer_1) + self.wait_for_home_page() + + # Register volunteers + volunteer_1 = create_volunteer_with_details(self.volunteer_1) shift = ['09:00', '15:00', '1'] - s1 = self.create_shift(shift) + shift_1 = self.create_shift(shift) - # open manage volunteer shift + # Open manage volunteer shift manage_shift_page.navigate_to_manage_shift_page() - # volunteer-one does not have any registered shifts + # Volunteer-one does not have any registered shifts manage_shift_page.select_volunteer(1) self.assertEqual(manage_shift_page.get_info_box(), manage_shift_page.no_volunteer_shift_message) manage_shift_page.assign_shift() - # events shown in table - with self.assertRaises(NoSuchElementException): - sign_up_page.get_info_box().text + # Events shown in table + self.assertRaisesRegexp(NoSuchElementException, + 'Unable to locate element: .alert-info', + sign_up_page.get_info_box) + sign_up_page.click_to_view_jobs() sign_up_page.click_to_view_shifts() - # arrived on shifts page, assign shift to volunteer one + # Arrived on shifts page, assign shift to volunteer one slots_remaining_before_assignment = sign_up_page.get_remaining_slots() sign_up_page.click_to_sign_up() - # confirm on shift assignment to volunteer-one + # Confirm on shift assignment to volunteer-one sign_up_page.submit_form() - with self.assertRaises(NoSuchElementException): - sign_up_page.get_danger_box() + self.assertRaisesRegexp(NoSuchElementException, + 'Unable to locate element: .alert-danger', + sign_up_page.get_danger_box) - # check shift assignment to volunteer-one + # Check shift assignment to volunteer-one manage_shift_page.navigate_to_manage_shift_page() manage_shift_page.select_volunteer(1) self.check_job_details( - ['job name', 'May 20, 2017', '9 a.m.', '3 p.m.']) - - # database check to ensure volunteer is registered - self.assertEqual(len(VolunteerShift.objects.all()), 1) + ['job name', 'May 20, 2050', '9 a.m.', '3 p.m.']) - # cancel assigned shift + # Cancel assigned shift self.assertEqual(manage_shift_page.get_cancel_shift().text, 'Cancel Shift Registration') manage_shift_page.cancel_shift() @@ -374,11 +461,17 @@ def test_cancel_assigned_shift(self): 'Yes, Cancel this Shift') manage_shift_page.submit_form() - # check cancelled shift reflects in volunteer shift details + self.wait.until( + EC.presence_of_element_located( + (By.CLASS_NAME, 'alert-info') + ) + ) + + # Check cancelled shift reflects in volunteer shift details self.assertEqual(manage_shift_page.get_info_box(), manage_shift_page.no_volunteer_shift_message) - # check slots remaining increases by one, after cancellation of + # Check slots remaining increases by one, after cancellation of # assigned shift manage_shift_page.assign_shift() sign_up_page.click_to_view_jobs() @@ -387,47 +480,49 @@ def test_cancel_assigned_shift(self): self.assertEqual(slots_remaining_before_assignment, slots_after_cancellation) - # database check to ensure registration is cancelled - self.assertEqual(len(VolunteerShift.objects.all()), 0) - def test_assign_same_shift_to_volunteer_twice(self): + """ + Test errors while assignment of same shift to volunteer to which they are already assigned. + """ sign_up_page = self.sign_up_page manage_shift_page = self.manage_shift_page self.manage_shift_page.live_server_url = self.live_server_url - # register volunteers - v1 = create_volunteer_with_details(self.volunteer_1) + # Register volunteers + volunteer_1 = create_volunteer_with_details(self.volunteer_1) shift = ['09:00', '15:00', '1'] - s1 = self.create_shift(shift) + shift_1 = self.create_shift(shift) + + self.wait_for_home_page() - # open manage volunteer shift + # Open manage volunteer shift manage_shift_page.navigate_to_manage_shift_page() - # volunteer-one does not have any registered shifts + # Volunteer-one does not have any registered shifts manage_shift_page.select_volunteer(1) self.assertEqual(manage_shift_page.get_info_box(), manage_shift_page.no_volunteer_shift_message) manage_shift_page.assign_shift() - # events shown in table - with self.assertRaises(NoSuchElementException): - sign_up_page.get_info_box() + # Events shown in table + self.assertRaisesRegexp(NoSuchElementException, + 'Unable to locate element: .alert-info', + sign_up_page.get_info_box) manage_shift_page.navigate_to_shift_assignment_page() - # confirm on shift assignment to volunteer-one + # Confirm on shift assignment to volunteer-one manage_shift_page.submit_form() - with self.assertRaises(NoSuchElementException): - sign_up_page.get_danger_box() + self.assertRaisesRegexp(NoSuchElementException, + 'Unable to locate element: .alert-danger', + sign_up_page.get_danger_box) - # assign same shift to voluteer-one again + # Assign same shift to voluteer-one again # Check volunteer-one has one registered shift now self.assertEqual(sign_up_page.get_shift_job(), 'job name') manage_shift_page.assign_shift() - # events page -<<<<<<< f64a1858806b1098016efb6eece6ad168ada09fd + # Events page self.assertEqual(sign_up_page.get_info_box().text,sign_up_page.no_event_message) -""" diff --git a/vms/shift/tests/test_services.py b/vms/shift/tests/test_services.py index 972807c..20e3852 100644 --- a/vms/shift/tests/test_services.py +++ b/vms/shift/tests/test_services.py @@ -1,936 +1,936 @@ -# standard library -import datetime -import unittest -from datetime import date, timedelta - -# Django -from django.core.exceptions import ObjectDoesNotExist - -# local Django -from shift.models import VolunteerShift -from shift.services import ( - add_shift_hours, calculate_duration, calculate_total_report_hours, - cancel_shift_registration, clear_shift_hours, delete_shift, - edit_shift_hours, generate_report, get_all_volunteer_shifts_with_hours, - get_shift_by_id, get_shifts_by_job_id, get_shifts_ordered_by_date, - get_shift_slots_remaining, get_shifts_with_open_slots, - get_unlogged_shifts_by_volunteer_id, get_volunteer_shift_by_id, - get_volunteer_shifts_with_hours, get_volunteers_by_shift_id, - get_logged_volunteers_by_shift_id, is_signed_up, register, send_reminder, - get_shifts_with_open_slots_for_volunteer, get_volunteer_report, - get_administrator_report) -from shift.utils import create_event_with_details, create_job_with_details, create_shift_with_details, clear_objects, get_report_list, create_volunteer_with_details, set_shift_location - - -def setUpModule(): - """ - - Creates objects which can be reused by multiple test classes - - Creates shifts with limited slots and with multiple slots for use - """ - - global e1 - global j1, j2 - global s1, s2, s3 - - event_1 = ["Open Source Event", "2012-9-1", "2012-11-23"] - e1 = create_event_with_details(event_1) - - job_1 = [ - "Software Developer", "2012-10-22", "2012-10-30", "A software job", e1 - ] - job_2 = [ - "Systems Administrator", "2012-9-1", "2012-10-26", - "A systems administrator job", e1 - ] - j1 = create_job_with_details(job_1) - j2 = create_job_with_details(job_2) - - shift_1 = ["2012-10-28", "9:00", "15:00", 1, j1] - shift_2 = ["2012-10-25", "10:00", "16:00", 2, j1] - shift_3 = ["2012-10-22", "10:00", "16:00", 4, j2] - - s1 = create_shift_with_details(shift_1) - s2 = create_shift_with_details(shift_2) - s3 = create_shift_with_details(shift_3) - - -def tearDownModule(): - # Destroys all objects created - clear_objects() - - -class ShiftTests(unittest.TestCase): - ''' - Contains tests which require - - only shift objects - - no objects to be created - ''' - - @classmethod - def setup_test_data(cls): - - cls.e1 = e1 - cls.j2 = j2 - cls.j1 = j1 - cls.s1 = s1 - cls.s2 = s2 - cls.s3 = s3 - - @classmethod - def setUpClass(cls): - cls.setup_test_data() - - @classmethod - def tearDownClass(cls): - pass - - def test_calculate_total_report_hours(self): - - duration_list = [1, 1, 1, 1] - report_list = [] - total_hours = 0 - - report_list, total_hours = get_report_list(duration_list, report_list, - total_hours) - - self.assertEqual( - calculate_total_report_hours(report_list), total_hours) - - duration_list = [0.03, 0.023, 0.53, 0.863, 0.23, 0.57] - report_list = [] - total_hours = 0 - - report_list, total_hours = get_report_list(duration_list, report_list, - total_hours) - - self.assertEqual( - calculate_total_report_hours(report_list), total_hours) - - duration_list = [12, 24, 23.5, 15.67, 22.453, 3.42] - report_list = [] - total_hours = 0 - - report_list, total_hours = get_report_list(duration_list, report_list, - total_hours) - - self.assertEqual( - calculate_total_report_hours(report_list), total_hours) - - duration_list = [5] - report_list = [] - total_hours = 0 - - report_list, total_hours = get_report_list(duration_list, report_list, - total_hours) - - self.assertEqual( - calculate_total_report_hours(report_list), total_hours) - - duration_list = [0, 0, 0, 0] - report_list = [] - total_hours = 0 - - report_list, total_hours = get_report_list(duration_list, report_list, - total_hours) - - self.assertEqual( - calculate_total_report_hours(report_list), total_hours) - - def test_calculate_duration(self): - - start_time = datetime.time(hour=1, minute=0) - end_time = datetime.time(hour=2, minute=0) - delta_time_hours = 1 - self.assertEqual( - calculate_duration(start_time, end_time), delta_time_hours) - - start_time = datetime.time(hour=1, minute=45) - end_time = datetime.time(hour=2, minute=0) - delta_time_hours = 0.25 - self.assertEqual( - calculate_duration(start_time, end_time), delta_time_hours) - - start_time = datetime.time(hour=1, minute=0) - end_time = datetime.time(hour=13, minute=0) - delta_time_hours = 12 - self.assertEqual( - calculate_duration(start_time, end_time), delta_time_hours) - - start_time = datetime.time(hour=1, minute=0) - end_time = datetime.time(hour=1, minute=0) - delta_time_hours = 0 - self.assertEqual( - calculate_duration(start_time, end_time), delta_time_hours) - - start_time = datetime.time(hour=22, minute=0) - end_time = datetime.time(hour=1, minute=0) - delta_time_hours = 3 - self.assertEqual( - calculate_duration(start_time, end_time), delta_time_hours) - - start_time = datetime.time(hour=13, minute=0) - end_time = datetime.time(hour=1, minute=0) - delta_time_hours = 12 - self.assertEqual( - calculate_duration(start_time, end_time), delta_time_hours) - - def test_get_shift_by_id(self): - """ Uses shifts s1 and s2 """ - - # test typical cases - self.assertIsNotNone(get_shift_by_id(self.s1.id)) - self.assertIsNotNone(get_shift_by_id(self.s2.id)) - - self.assertEqual(get_shift_by_id(self.s1.id), self.s1) - self.assertEqual(get_shift_by_id(self.s2.id), self.s2) - - # test non-existant cases - self.assertIsNone(get_shift_by_id(100)) - self.assertIsNone(get_shift_by_id(200)) - - def test_get_shifts_by_job_id(self): - """ - Test get_shifts_by_job_id(j_id) - Uses job j1 - """ - job_1_shifts = get_shifts_by_job_id(j1.id) - job_2_shifts = get_shifts_by_job_id(j2.id) - - self.assertIsNotNone(get_shifts_by_job_id(j1.id)) - self.assertIsNotNone(get_shifts_by_job_id(j2.id)) - - self.assertEqual(len(job_1_shifts), 2) - self.assertEqual(len(job_2_shifts), 1) - - def test_get_shifts_ordered_by_date(self): - """ Uses shifts s1 and s2 """ - - # test typical case - shift_list = get_shifts_ordered_by_date(self.j1.id) - self.assertIsNotNone(shift_list) - self.assertNotEqual(shift_list, False) - self.assertEqual(len(shift_list), 2) - self.assertIn(self.s1, shift_list) - self.assertIn(self.s2, shift_list) - - # test order - self.assertEqual(shift_list[0], self.s2) - self.assertEqual(shift_list[1], self.s1) - - -class ShiftWithVolunteerTest(unittest.TestCase): - ''' - Contains tests which require volunteer object - ''' - - @classmethod - def setup_test_data(cls): - - cls.e1 = e1 - cls.j1 = j1 - cls.j2 = j2 - cls.s1 = s1 - cls.s2 = s2 - cls.s3 = s3 - - # Create volunteers who will register for the shifts - volunteer_1 = [ - 'Yoshi', "Yoshi", "Turtle", "Mario Land", "Nintendo Land", - "Nintendo State", "Nintendo Nation", "2374983247", - "yoshi@nintendo.com" - ] - volunteer_2 = [ - 'John', "John", "Doe", "7 Alpine Street", "Maplegrove", "Wyoming", - "USA", "23454545", "john@test.com" - ] - volunteer_3 = [ - 'Ash', "Ash", "Ketchum", "Pallet Town", "Kanto", "Gameboy", - "Japan", "23454545", "ash@pikachu.com" - ] - - cls.v1 = create_volunteer_with_details(volunteer_1) - cls.v2 = create_volunteer_with_details(volunteer_2) - cls.v3 = create_volunteer_with_details(volunteer_3) - - @classmethod - def setUpClass(cls): - cls.setup_test_data() - - def tearDown(self): - # remove all registered volunteers - VolunteerShift.objects.all().delete() - - def test_get_shifts_with_open_slots_for_volunteer(self): - """ Uses volunteer v1, v2 """ - - register(self.v1.id, self.s2.id) - register(self.v2.id, self.s1.id) - - open_slots_1 = get_shifts_with_open_slots_for_volunteer( - self.j1.id, self.v1.id) - open_slots_2 = get_shifts_with_open_slots_for_volunteer( - self.j2.id, self.v1.id) - - self.assertIsNotNone(open_slots_1) - self.assertIsNotNone(open_slots_2) - self.assertEqual(len(open_slots_1), 0) - self.assertEqual(len(open_slots_2), 1) - - self.assertEqual(self.s3.id, open_slots_2[0]["id"]) - - def test_get_volunteer_report(self): - - # register volunteer for 2 shifts, log hours for one - register(self.v1.id, self.s1.id) - register(self.v1.id, self.s3.id) - - start_time = datetime.time(hour=9, minute=0) - end_time = datetime.time(hour=10, minute=0) - add_shift_hours(self.v1.id, self.s1.id, start_time, end_time) - - report_1 = get_volunteer_report(self.v1.id, self.e1.name, self.j1.name, - "2012-10-22", "2012-10-30") - report_2 = get_volunteer_report(self.v1.id, self.e1.name, self.j2.name, - "2012-9-1", "2012-10-26") - - # verify that report for logged shift appears - self.assertEqual(len(report_1), 1) - self.assertEqual(len(report_2), 0) - self.assertEqual(self.e1.name, report_1[0]["event_name"]) - self.assertEqual(self.j1.name, report_1[0]["job_name"]) - - # commented out due to bug #327 - # self.assertEqual(start_time, report_1[0]["logged_start_time"]) - # self.assertEqual(end_time, report_1[0]["logged_end_time"]) - # self.assertEqual(1.0, report_1[0]["duration"]) - - def test_get_administrator_report(self): - - register(self.v1.id, self.s1.id) - register(self.v2.id, self.s3.id) - - start_time = datetime.time(hour=11, minute=0) - end_time = datetime.time(hour=12, minute=0) - add_shift_hours(self.v1.id, self.s1.id, start_time, end_time) - add_shift_hours(self.v2.id, self.s3.id, start_time, end_time) - - report_1 = get_administrator_report(self.v1.first_name, "", "", - self.e1.name, self.j1.name, - "2012-10-22", "2012-10-30") - report_2 = get_administrator_report(self.v1.first_name, "", "", - self.e1.name, self.j2.name, - "2012-9-1", "2012-10-26") - report_3 = get_administrator_report("", "", "", self.e1.name, - self.j2.name, "", "") - - # verify that report for logged shift appears - self.assertEqual(len(report_1), 1) - self.assertEqual(len(report_2), 0) - self.assertEqual(len(report_3), 1) - self.assertEqual(self.v1.first_name, report_1[0]["first_name"]) - self.assertEqual(self.v2.first_name, report_3[0]["first_name"]) - - # commented out due to bug #327 - # self.assertEqual(start_time, report_1[0]["logged_start_time"]) - # self.assertEqual(start_time, report_3[0]["logged_start_time"]) - # self.assertEqual(end_time, report_1[0]["logged_end_time"]) - # self.assertEqual(end_time, report_3[0]["logged_end_time"]) - # self.assertEqual(1.0, report_1[0]["duration"]) - # self.assertEqual(1.0, report_3[0]["duration"]) - - def test_add_shift_hours(self): - """ Uses shifts s1, s2, s3 and volunteers v1,v2,v3 """ - - # register will return an exception on error - # (such as when invalid parameters are passed) - # if an exception does get raised, this test will automatically fail - register(self.v1.id, self.s1.id) - self.assertIsNotNone( - VolunteerShift.objects.get( - volunteer_id=self.v1.id, shift_id=self.s1.id)) - - register(self.v1.id, self.s2.id) - self.assertIsNotNone( - VolunteerShift.objects.get( - volunteer_id=self.v1.id, shift_id=self.s2.id)) - - register(self.v1.id, self.s3.id) - self.assertIsNotNone( - VolunteerShift.objects.get( - volunteer_id=self.v1.id, shift_id=self.s3.id)) - - start_time = datetime.time(hour=9, minute=0) - end_time = datetime.time(hour=10, minute=0) - add_shift_hours(self.v1.id, self.s1.id, start_time, end_time) - volunteer_shift = VolunteerShift.objects.get( - volunteer_id=self.v1.id, shift_id=self.s1.id) - self.assertEqual(volunteer_shift.start_time, start_time) - self.assertEqual(volunteer_shift.end_time, end_time) - - start_time = datetime.time(hour=10, minute=0) - end_time = datetime.time(hour=12, minute=0) - add_shift_hours(self.v1.id, self.s2.id, start_time, end_time) - volunteer_shift = VolunteerShift.objects.get( - volunteer_id=self.v1.id, shift_id=self.s2.id) - self.assertEqual(volunteer_shift.start_time, start_time) - self.assertEqual(volunteer_shift.end_time, end_time) - - start_time = datetime.time(hour=5, minute=0) - end_time = datetime.time(hour=6, minute=0) - add_shift_hours(self.v1.id, self.s3.id, start_time, end_time) - volunteer_shift = VolunteerShift.objects.get( - volunteer_id=self.v1.id, shift_id=self.s3.id) - self.assertEqual(volunteer_shift.start_time, start_time) - self.assertEqual(volunteer_shift.end_time, end_time) - - def test_cancel_shift_registration(self): - """ Uses shifts s1, s2, s3 and volunteers v1,v2 """ - - # test cases when try to cancel when they aren't signed up for a shift - with self.assertRaises(ObjectDoesNotExist): - cancel_shift_registration(self.v1.id, self.s1.id) - - with self.assertRaises(ObjectDoesNotExist): - cancel_shift_registration(self.v1.id, self.s2.id) - - with self.assertRaises(ObjectDoesNotExist): - cancel_shift_registration(self.v2.id, self.s1.id) - - # register volunteers to shifts - register(self.v1.id, self.s1.id) - register(self.v2.id, self.s1.id) - register(self.v2.id, self.s2.id) - - # test typical cases - cancel_shift_registration(self.v1.id, self.s1.id) - - with self.assertRaises(ObjectDoesNotExist): - cancel_shift_registration(self.v2.id, self.s1.id) - - cancel_shift_registration(self.v2.id, self.s2.id) - - def test_clear_shift_hours(self): - """ Uses shifts s1, s2, s3 and volunteer v1 """ - - register(self.v1.id, self.s1.id) - self.assertIsNotNone( - VolunteerShift.objects.get( - volunteer_id=self.v1.id, shift_id=self.s1.id)) - - register(self.v1.id, self.s2.id) - self.assertIsNotNone( - VolunteerShift.objects.get( - volunteer_id=self.v1.id, shift_id=self.s2.id)) - - register(self.v1.id, self.s3.id) - self.assertIsNotNone( - VolunteerShift.objects.get( - volunteer_id=self.v1.id, shift_id=self.s3.id)) - - start_time = datetime.time(hour=9, minute=0) - end_time = datetime.time(hour=10, minute=0) - add_shift_hours(self.v1.id, self.s1.id, start_time, end_time) - - start_time = datetime.time(hour=10, minute=0) - end_time = datetime.time(hour=12, minute=0) - add_shift_hours(self.v1.id, self.s2.id, start_time, end_time) - - start_time = datetime.time(hour=5, minute=0) - end_time = datetime.time(hour=6, minute=0) - add_shift_hours(self.v1.id, self.s3.id, start_time, end_time) - - clear_shift_hours(self.v1.id, self.s1.id) - volunteer_shift = VolunteerShift.objects.get( - volunteer_id=self.v1.id, shift_id=self.s1.id) - self.assertIsNone(volunteer_shift.start_time) - self.assertIsNone(volunteer_shift.end_time) - - clear_shift_hours(self.v1.id, self.s2.id) - volunteer_shift = VolunteerShift.objects.get( - volunteer_id=self.v1.id, shift_id=self.s2.id) - self.assertIsNone(volunteer_shift.start_time) - self.assertIsNone(volunteer_shift.end_time) - - clear_shift_hours(self.v1.id, self.s3.id) - volunteer_shift = VolunteerShift.objects.get( - volunteer_id=self.v1.id, shift_id=self.s3.id) - self.assertIsNone(volunteer_shift.start_time) - self.assertIsNone(volunteer_shift.end_time) - - def test_edit_shift_hours(self): - """ Uses shift s1 and volunteer v1 """ - - register(self.v1.id, self.s1.id) - self.assertIsNotNone( - VolunteerShift.objects.get( - volunteer_id=self.v1.id, shift_id=self.s1.id)) - - start_time = datetime.time(hour=9, minute=0) - end_time = datetime.time(hour=10, minute=0) - add_shift_hours(self.v1.id, self.s1.id, start_time, end_time) - - start_time = datetime.time(hour=10, minute=0) - end_time = datetime.time(hour=11, minute=0) - edit_shift_hours(self.v1.id, self.s1.id, start_time, end_time) - volunteer_shift = VolunteerShift.objects.get( - volunteer_id=self.v1.id, shift_id=self.s1.id) - self.assertIsNotNone(volunteer_shift.start_time) - self.assertIsNotNone(volunteer_shift.end_time) - self.assertEqual(volunteer_shift.start_time, start_time) - self.assertEqual(volunteer_shift.end_time, end_time) - - start_time = datetime.time(hour=1, minute=0) - end_time = datetime.time(hour=4, minute=0) - edit_shift_hours(self.v1.id, self.s1.id, start_time, end_time) - volunteer_shift = VolunteerShift.objects.get( - volunteer_id=self.v1.id, shift_id=self.s1.id) - self.assertIsNotNone(volunteer_shift.start_time) - self.assertIsNotNone(volunteer_shift.end_time) - self.assertEqual(volunteer_shift.start_time, start_time) - self.assertEqual(volunteer_shift.end_time, end_time) - - start_time = datetime.time(hour=4, minute=15) - end_time = datetime.time(hour=12, minute=35) - edit_shift_hours(self.v1.id, self.s1.id, start_time, end_time) - volunteer_shift = VolunteerShift.objects.get( - volunteer_id=self.v1.id, shift_id=self.s1.id) - self.assertIsNotNone(volunteer_shift.start_time) - self.assertIsNotNone(volunteer_shift.end_time) - self.assertEqual(volunteer_shift.start_time, start_time) - self.assertEqual(volunteer_shift.end_time, end_time) - - start_time = datetime.time(hour=2, minute=5) - end_time = datetime.time(hour=4, minute=15) - edit_shift_hours(self.v1.id, self.s1.id, start_time, end_time) - volunteer_shift = VolunteerShift.objects.get( - volunteer_id=self.v1.id, shift_id=self.s1.id) - self.assertIsNotNone(volunteer_shift.start_time) - self.assertIsNotNone(volunteer_shift.end_time) - self.assertEqual(volunteer_shift.start_time, start_time) - self.assertEqual(volunteer_shift.end_time, end_time) - - start_time = datetime.time(hour=5, minute=0) - end_time = datetime.time(hour=5, minute=30) - edit_shift_hours(self.v1.id, self.s1.id, start_time, end_time) - volunteer_shift = VolunteerShift.objects.get( - volunteer_id=self.v1.id, shift_id=self.s1.id) - self.assertIsNotNone(volunteer_shift.start_time) - self.assertIsNotNone(volunteer_shift.end_time) - self.assertEqual(volunteer_shift.start_time, start_time) - self.assertEqual(volunteer_shift.end_time, end_time) - - def test_generate_report(self): - """ Uses shifts s1, s2 and volunteer v1 - Tests test_generate_report(volunteer_shift_list) """ - - # register will return an exception on error - # (such as when invalid parameters are passed) - # if an exception does get raised, this test will automatically fail - start_time = datetime.time(hour=9, minute=0) - end_time = datetime.time(hour=10, minute=0) - register(self.v1.id, self.s1.id) - add_shift_hours(self.v1.id, self.s1.id, start_time, end_time) - volunteer_shift_1 = VolunteerShift.objects.get( - volunteer_id=self.v1.id, shift_id=self.s1.id) - self.assertIsNotNone(volunteer_shift_1) - - register(self.v1.id, self.s2.id) - add_shift_hours(self.v1.id, self.s2.id, start_time, end_time) - volunteer_shift_2 = VolunteerShift.objects.get( - volunteer_id=self.v1.id, shift_id=self.s2.id) - self.assertIsNotNone(volunteer_shift_2) - - volunteer_shift_list = [volunteer_shift_1, volunteer_shift_2] - - reports = generate_report(volunteer_shift_list) - self.assertEqual(len(reports), 2) - self.assertIsNotNone(reports) - - def test_get_all_volunteer_shifts_with_hours(self): - # Test get_all_volunteer_shifts_with_hours() - register(self.v1.id, self.s1.id) - register(self.v2.id, self.s2.id) - - start_time = datetime.time(hour=9, minute=0) - end_time = datetime.time(hour=10, minute=0) - - add_shift_hours(self.v1.id, self.s1.id, start_time, end_time) - hours_list = get_all_volunteer_shifts_with_hours() - - self.assertEqual(len(hours_list), 1) - self.assertEqual(self.v1.id, hours_list[0].volunteer_id) - self.assertEqual(self.s1.id, hours_list[0].shift_id) - - self.assertIsNotNone(get_all_volunteer_shifts_with_hours()) - - def test_get_shift_slots_remaining(self): - """ Uses shifts s1, s2, s3 - Tests get_shift_slots_remaining(s_id) """ - - register(self.v1.id, self.s1.id) - register(self.v2.id, self.s3.id) - register(self.v3.id, self.s3.id) - - slots_s1 = get_shift_slots_remaining(self.s1.id) - slots_s2 = get_shift_slots_remaining(self.s2.id) - slots_s3 = get_shift_slots_remaining(self.s3.id) - - self.assertIsNotNone(slots_s1) - self.assertIsNotNone(slots_s2) - self.assertIsNotNone(slots_s3) - - self.assertEqual(slots_s1, 0) - self.assertEqual(slots_s2, 2) - self.assertEqual(slots_s3, 2) - - def test_get_shifts_with_open_slots(self): - """ Uses jobs j1, j2 - Tests get_shifts_with_open_slots(j_id) """ - - register(self.v1.id, self.s1.id) - register(self.v2.id, self.s3.id) - - shift_list_1 = get_shifts_with_open_slots(self.j1.id) - shift_list_2 = get_shifts_with_open_slots(self.j2.id) - - self.assertIsNotNone(shift_list_1) - self.assertIsNotNone(shift_list_2) - self.assertEqual(len(shift_list_1), 1) - self.assertEqual(len(shift_list_2), 1) - - self.assertNotEqual(self.s1.id, shift_list_1[0]["id"]) - self.assertEqual(self.s2.id, shift_list_1[0]["id"]) - self.assertEqual(self.s3.id, shift_list_2[0]["id"]) - - def test_get_unlogged_shifts_by_volunteer_id(self): - """ Uses shifts s1, s2 and volunteer v1 """ - - # sign up - register(self.v1.id, self.s1.id) - register(self.v1.id, self.s2.id) - - start_time = datetime.time(hour=9, minute=0) - end_time = datetime.time(hour=10, minute=0) - - add_shift_hours(self.v1.id, self.s1.id, start_time, end_time) - - # test typical case - shift_list = get_unlogged_shifts_by_volunteer_id(self.v1.id) - self.assertIsNotNone(shift_list) - self.assertNotEqual(shift_list, False) - self.assertEqual(len(shift_list), 1) - self.assertNotIn(self.s1, shift_list) - self.assertIn(self.s2, shift_list) - self.assertNotIn(self.s3, shift_list) - - def test_get_volunteer_shift_by_id(self): - """ Uses shifts s1,s2,s3 and volunteers v1,v2""" - - # test cases where signed up - register(self.v1.id, self.s1.id) - register(self.v1.id, self.s2.id) - register(self.v1.id, self.s3.id) - - register(self.v2.id, self.s1.id) - register(self.v2.id, self.s2.id) - register(self.v2.id, self.s3.id) - - self.assertEqual( - get_volunteer_shift_by_id(self.v1.id, self.s1.id), - VolunteerShift.objects.get( - volunteer_id=self.v1.id, shift_id=self.s1.id)) - self.assertEqual( - get_volunteer_shift_by_id(self.v1.id, self.s2.id), - VolunteerShift.objects.get( - volunteer_id=self.v1.id, shift_id=self.s2.id)) - self.assertEqual( - get_volunteer_shift_by_id(self.v1.id, self.s3.id), - VolunteerShift.objects.get( - volunteer_id=self.v1.id, shift_id=self.s3.id)) - - # self.assertEqual(get_volunteer_shift_by_id(v2.id, s1.id), - # VolunteerShift.objects.get(volunteer_id=v2.id, shift_id=s1.id)) - # why does this throw DoesNotExist? - self.assertEqual( - get_volunteer_shift_by_id(self.v2.id, self.s2.id), - VolunteerShift.objects.get( - volunteer_id=self.v2.id, shift_id=self.s2.id)) - self.assertEqual( - get_volunteer_shift_by_id(self.v2.id, self.s3.id), - VolunteerShift.objects.get( - volunteer_id=self.v2.id, shift_id=self.s3.id)) - - def test_get_volunteer_shifts_with_hours(self): - """ Uses volunteers v1 and v2 - Test get_volunteer_shifts_with_hours(v_id) """ - - register(self.v1.id, self.s1.id) - register(self.v1.id, self.s2.id) - - start_time = datetime.time(hour=9, minute=0) - end_time = datetime.time(hour=10, minute=0) - - add_shift_hours(self.v1.id, self.s1.id, start_time, end_time) - - v1_hours = get_volunteer_shifts_with_hours(self.v1) - v2_hours = get_volunteer_shifts_with_hours(self.v2) - - self.assertIsNotNone(get_volunteer_shifts_with_hours(self.v1)) - self.assertIsNotNone(get_volunteer_shifts_with_hours(self.v2)) - - self.assertEqual(len(v1_hours), 1) - self.assertEqual(self.s1.id, v1_hours[0].shift_id) - self.assertEqual(len(v2_hours), 0) - - def test_get_volunteers_by_shift_id(self): - """ Uses volunteers v1,v2,v3 and shifts s1,s2,s3 """ - - # sign up - register(self.v3.id, self.s1.id) - register(self.v1.id, self.s1.id) - register(self.v1.id, self.s3.id) - register(self.v3.id, self.s3.id) - register(self.v2.id, self.s3.id) - - # get volunteer lists - volunteer_list_for_shift_1 = get_volunteers_by_shift_id(self.s1.id) - volunteer_list_for_shift_2 = get_volunteers_by_shift_id(self.s2.id) - volunteer_list_for_shift_3 = get_volunteers_by_shift_id(self.s3.id) - - # test typical case - self.assertEqual(len(volunteer_list_for_shift_1), 1) - self.assertEqual(len(volunteer_list_for_shift_2), 0) - self.assertEqual(len(volunteer_list_for_shift_3), 3) - - self.assertIn(self.v3, volunteer_list_for_shift_1) - self.assertNotIn(self.v1, volunteer_list_for_shift_1) - self.assertIn(self.v1, volunteer_list_for_shift_3) - self.assertIn(self.v2, volunteer_list_for_shift_3) - self.assertIn(self.v3, volunteer_list_for_shift_3) - - # test order - self.assertEqual(volunteer_list_for_shift_3[0], self.v3) - self.assertEqual(volunteer_list_for_shift_3[1], self.v2) - self.assertEqual(volunteer_list_for_shift_3[2], self.v1) - - def test_get_logged_volunteers_by_shift_id(self): - """ Uses volunteers v1,v2,v3 and shift s3 """ - - # sign up - register(self.v3.id, self.s3.id) - register(self.v1.id, self.s3.id) - register(self.v2.id, self.s3.id) - - start_time = datetime.time(hour=1, minute=0) - end_time = datetime.time(hour=2, minute=0) - add_shift_hours(self.v1.id, self.s3.id, start_time, end_time) - - start_time = datetime.time(hour=2, minute=0) - end_time = datetime.time(hour=3, minute=0) - add_shift_hours(self.v3.id, self.s3.id, start_time, end_time) - - # get volunteer list - logged_volunteer_list_for_shift = get_logged_volunteers_by_shift_id( - self.s3.id) - - # test typical case and order - self.assertEqual(len(logged_volunteer_list_for_shift), 2) - self.assertEqual(logged_volunteer_list_for_shift[0].volunteer, self.v3) - self.assertEqual(logged_volunteer_list_for_shift[1].volunteer, self.v1) - - def test_is_signed_up(self): - """ Uses volunteers v1,v2 and shifts s1,s2,s3 """ - - # test cases where not signed up yet - self.assertFalse(is_signed_up(self.v1.id, self.s1.id)) - self.assertFalse(is_signed_up(self.v1.id, self.s2.id)) - self.assertFalse(is_signed_up(self.v1.id, self.s3.id)) - - # test cases where signed up - register(self.v1.id, self.s1.id) - register(self.v1.id, self.s2.id) - register(self.v1.id, self.s3.id) - - self.assertTrue(is_signed_up(self.v1.id, self.s1.id)) - self.assertTrue(is_signed_up(self.v1.id, self.s2.id)) - self.assertTrue(is_signed_up(self.v1.id, self.s3.id)) - - # test case where more than one volunteer signs up for the same shift - self.assertFalse(is_signed_up(self.v2.id, self.s1.id)) - self.assertFalse(is_signed_up(self.v2.id, self.s2.id)) - self.assertFalse(is_signed_up(self.v2.id, self.s3.id)) - - register(self.v2.id, self.s2.id) - register(self.v2.id, self.s3.id) - - self.assertFalse(is_signed_up(self.v2.id, self.s1.id)) - self.assertTrue(is_signed_up(self.v2.id, self.s2.id)) - self.assertTrue(is_signed_up(self.v2.id, self.s3.id)) - - def test_register(self): - """ Uses volunteers v1,v2 and shifts s1,s2,s3 """ - - ERROR_CODE_ALREADY_SIGNED_UP = "ERROR_CODE_ALREADY_SIGNED_UP" - ERROR_CODE_NO_SLOTS_REMAINING = "ERROR_CODE_NO_SLOTS_REMAINING" - - # test typical cases - register(self.v1.id, self.s1.id) - self.assertIsNotNone( - VolunteerShift.objects.get( - volunteer_id=self.v1.id, shift_id=self.s1.id)) - - register(self.v1.id, self.s2.id) - self.assertIsNotNone( - VolunteerShift.objects.get( - volunteer_id=self.v1.id, shift_id=self.s2.id)) - - register(self.v1.id, self.s3.id) - self.assertIsNotNone( - VolunteerShift.objects.get( - volunteer_id=self.v1.id, shift_id=self.s3.id)) - - # test cases where volunteer tries to sign up for a shift - # they are already signed up for - self.assertEqual( - register(self.v1.id, self.s1.id), ERROR_CODE_ALREADY_SIGNED_UP) - self.assertEqual( - register(self.v1.id, self.s2.id), ERROR_CODE_ALREADY_SIGNED_UP) - self.assertEqual( - register(self.v1.id, self.s3.id), ERROR_CODE_ALREADY_SIGNED_UP) - - # test case where more than one volunteer signs up for the same shift - # v2 can't sign up for s1 because there are no slots remaining - self.assertEqual( - register(self.v2.id, self.s1.id), ERROR_CODE_NO_SLOTS_REMAINING) - - register(self.v2.id, self.s2.id) - self.assertIsNotNone( - VolunteerShift.objects.get( - volunteer_id=self.v2.id, shift_id=self.s2.id)) - - register(self.v2.id, self.s3.id) - self.assertIsNotNone( - VolunteerShift.objects.get( - volunteer_id=self.v2.id, shift_id=self.s3.id)) - - # test cases where a volunteer tries to sign up for a shift - # they are already signed up for - self.assertEqual( - register(self.v2.id, self.s2.id), ERROR_CODE_ALREADY_SIGNED_UP) - self.assertEqual( - register(self.v2.id, self.s3.id), ERROR_CODE_ALREADY_SIGNED_UP) - - -class ShiftReminderTest(unittest.TestCase): - @classmethod - def setup_test_data(cls): - - cls.e1 = e1 - cls.j1 = j1 - cls.j2 = j2 - - shift_1 = ["2015-08-23", "9:00", "15:00", 1, cls.j1] - shift_2 = [date.today() + timedelta(7), "10:00", "16:00", 2, - cls.j1] # one week date - shift_3 = [date.today() + timedelta(1), "12:00", "18:00", 2, - cls.j2] # tomorrow date - - cls.s1 = create_shift_with_details(shift_1) - cls.s2 = create_shift_with_details(shift_2) - cls.s3 = create_shift_with_details(shift_3) - - volunteer_1 = [ - 'Jake', "Jake", "Flamoy", "Mario Land", "Nintendo Land", - "Nintendo State", "Nintendo Nation", "2374983247", - "jake@nintendo.com" - ] - volunteer_2 = [ - 'Dora', "Dorothy", "Flamoy", "7 Alpine Street", "Maplegrove", - "Wyoming", "USA", "23454545", "dora@test.com" - ] - - cls.v1 = create_volunteer_with_details(volunteer_1) - cls.v2 = create_volunteer_with_details(volunteer_2) - - @classmethod - def setUpClass(cls): - cls.setup_test_data() - - @classmethod - def tearDownClass(cls): - cls.s1.delete() - cls.s2.delete() - cls.s3.delete() - - # remove all registered volunteers - VolunteerShift.objects.all().delete() - - def test_send_reminder(self): - - location = [ - "Test address", "Atlanta", "Georgia", "USA", - "Near the south entrance" - ] - - set_shift_location(self.s1, location) - set_shift_location(self.s2, location) - set_shift_location(self.s3, location) - - self.v1.reminder_days = 1 - self.v2.reminder_days = 7 - self.v1.save() - self.v2.save() - - # sign up - register(self.v1.id, self.s1.id) - register(self.v1.id, self.s2.id) - register(self.v1.id, self.s3.id) - register(self.v2.id, self.s1.id) - register(self.v2.id, self.s2.id) - register(self.v2.id, self.s3.id) - - # test typical case - result = send_reminder() - - self.assertEqual(result, 2) - - -class DeleteShiftTest(unittest.TestCase): - @classmethod - def setup_test_data(cls): - - cls.e1 = e1 - cls.j1 = j1 - - shift_1 = ["2012-10-28", "9:00", "15:00", 1, cls.j1] - shift_2 = ["2012-10-25", "10:00", "16:00", 2, cls.j1] - - cls.s1 = create_shift_with_details(shift_1) - cls.s2 = create_shift_with_details(shift_2) - - volunteer_1 = [ - 'Aaron', "Aaron", "Turtle", "Mario Land", "Nintendo Land", - "Nintendo State", "Nintendo Nation", "2374983247", - "aaron@nintendo.com" - ] - cls.v1 = create_volunteer_with_details(volunteer_1) - - @classmethod - def setUpClass(cls): - cls.setup_test_data() - - @classmethod - def tearDownClass(cls): - cls.s2.delete() - - # remove all registered volunteers - VolunteerShift.objects.all().delete() - - def test_delete_shift(self): - # Test delete_shift(shift_id) - - self.assertTrue(delete_shift(self.s1.id)) - self.assertFalse(delete_shift(100)) - - register(self.v1.id, self.s2.id) - self.assertFalse(delete_shift(self.s2.id)) +# standard library +import datetime +import unittest +from datetime import date, timedelta + +# Django +from django.core.exceptions import ObjectDoesNotExist + +# local Django +from shift.models import VolunteerShift +from shift.services import ( + add_shift_hours, calculate_duration, calculate_total_report_hours, + cancel_shift_registration, clear_shift_hours, delete_shift, + edit_shift_hours, generate_report, get_all_volunteer_shifts_with_hours, + get_shift_by_id, get_shifts_by_job_id, get_shifts_ordered_by_date, + get_shift_slots_remaining, get_shifts_with_open_slots, + get_unlogged_shifts_by_volunteer_id, get_volunteer_shift_by_id, + get_volunteer_shifts_with_hours, get_volunteers_by_shift_id, + get_logged_volunteers_by_shift_id, is_signed_up, register, send_reminder, + get_shifts_with_open_slots_for_volunteer, get_volunteer_report, + get_administrator_report) +from shift.utils import create_event_with_details, create_job_with_details, create_shift_with_details, clear_objects, get_report_list, create_volunteer_with_details, set_shift_location + + +def setUpModule(): + """ + - Creates objects which can be reused by multiple test classes + - Creates shifts with limited slots and with multiple slots for use + """ + + global e1 + global j1, j2 + global s1, s2, s3 + + event_1 = ["Open Source Event", "2012-9-1", "2012-11-23"] + e1 = create_event_with_details(event_1) + + job_1 = [ + "Software Developer", "2012-10-22", "2012-10-30", "A software job", e1 + ] + job_2 = [ + "Systems Administrator", "2012-9-1", "2012-10-26", + "A systems administrator job", e1 + ] + j1 = create_job_with_details(job_1) + j2 = create_job_with_details(job_2) + + shift_1 = ["2012-10-28", "9:00", "15:00", 1, j1] + shift_2 = ["2012-10-25", "10:00", "16:00", 2, j1] + shift_3 = ["2012-10-22", "10:00", "16:00", 4, j2] + + s1 = create_shift_with_details(shift_1) + s2 = create_shift_with_details(shift_2) + s3 = create_shift_with_details(shift_3) + + +def tearDownModule(): + # Destroys all objects created + clear_objects() + + +class ShiftTests(unittest.TestCase): + ''' + Contains tests which require + - only shift objects + - no objects to be created + ''' + + @classmethod + def setup_test_data(cls): + + cls.e1 = e1 + cls.j2 = j2 + cls.j1 = j1 + cls.s1 = s1 + cls.s2 = s2 + cls.s3 = s3 + + @classmethod + def setUpClass(cls): + cls.setup_test_data() + + @classmethod + def tearDownClass(cls): + pass + + def test_calculate_total_report_hours(self): + + duration_list = [1, 1, 1, 1] + report_list = [] + total_hours = 0 + + report_list, total_hours = get_report_list(duration_list, report_list, + total_hours) + + self.assertEqual( + calculate_total_report_hours(report_list), total_hours) + + duration_list = [0.03, 0.023, 0.53, 0.863, 0.23, 0.57] + report_list = [] + total_hours = 0 + + report_list, total_hours = get_report_list(duration_list, report_list, + total_hours) + + self.assertEqual( + calculate_total_report_hours(report_list), total_hours) + + duration_list = [12, 24, 23.5, 15.67, 22.453, 3.42] + report_list = [] + total_hours = 0 + + report_list, total_hours = get_report_list(duration_list, report_list, + total_hours) + + self.assertEqual( + calculate_total_report_hours(report_list), total_hours) + + duration_list = [5] + report_list = [] + total_hours = 0 + + report_list, total_hours = get_report_list(duration_list, report_list, + total_hours) + + self.assertEqual( + calculate_total_report_hours(report_list), total_hours) + + duration_list = [0, 0, 0, 0] + report_list = [] + total_hours = 0 + + report_list, total_hours = get_report_list(duration_list, report_list, + total_hours) + + self.assertEqual( + calculate_total_report_hours(report_list), total_hours) + + def test_calculate_duration(self): + + start_time = datetime.time(hour=1, minute=0) + end_time = datetime.time(hour=2, minute=0) + delta_time_hours = 1 + self.assertEqual( + calculate_duration(start_time, end_time), delta_time_hours) + + start_time = datetime.time(hour=1, minute=45) + end_time = datetime.time(hour=2, minute=0) + delta_time_hours = 0.25 + self.assertEqual( + calculate_duration(start_time, end_time), delta_time_hours) + + start_time = datetime.time(hour=1, minute=0) + end_time = datetime.time(hour=13, minute=0) + delta_time_hours = 12 + self.assertEqual( + calculate_duration(start_time, end_time), delta_time_hours) + + start_time = datetime.time(hour=1, minute=0) + end_time = datetime.time(hour=1, minute=0) + delta_time_hours = 0 + self.assertEqual( + calculate_duration(start_time, end_time), delta_time_hours) + + start_time = datetime.time(hour=22, minute=0) + end_time = datetime.time(hour=1, minute=0) + delta_time_hours = 3 + self.assertEqual( + calculate_duration(start_time, end_time), delta_time_hours) + + start_time = datetime.time(hour=13, minute=0) + end_time = datetime.time(hour=1, minute=0) + delta_time_hours = 12 + self.assertEqual( + calculate_duration(start_time, end_time), delta_time_hours) + + def test_get_shift_by_id(self): + """ Uses shifts s1 and s2 """ + + # test typical cases + self.assertIsNotNone(get_shift_by_id(self.s1.id)) + self.assertIsNotNone(get_shift_by_id(self.s2.id)) + + self.assertEqual(get_shift_by_id(self.s1.id), self.s1) + self.assertEqual(get_shift_by_id(self.s2.id), self.s2) + + # test non-existant cases + self.assertIsNone(get_shift_by_id(1000)) + self.assertIsNone(get_shift_by_id(2000)) + + def test_get_shifts_by_job_id(self): + """ + Test get_shifts_by_job_id(j_id) + Uses job j1 + """ + job_1_shifts = get_shifts_by_job_id(j1.id) + job_2_shifts = get_shifts_by_job_id(j2.id) + + self.assertIsNotNone(get_shifts_by_job_id(j1.id)) + self.assertIsNotNone(get_shifts_by_job_id(j2.id)) + + self.assertEqual(len(job_1_shifts), 2) + self.assertEqual(len(job_2_shifts), 1) + + def test_get_shifts_ordered_by_date(self): + """ Uses shifts s1 and s2 """ + + # test typical case + shift_list = get_shifts_ordered_by_date(self.j1.id) + self.assertIsNotNone(shift_list) + self.assertNotEqual(shift_list, False) + self.assertEqual(len(shift_list), 2) + self.assertIn(self.s1, shift_list) + self.assertIn(self.s2, shift_list) + + # test order + self.assertEqual(shift_list[0], self.s2) + self.assertEqual(shift_list[1], self.s1) + + +class ShiftWithVolunteerTest(unittest.TestCase): + ''' + Contains tests which require volunteer object + ''' + + @classmethod + def setup_test_data(cls): + + cls.e1 = e1 + cls.j1 = j1 + cls.j2 = j2 + cls.s1 = s1 + cls.s2 = s2 + cls.s3 = s3 + + # Create volunteers who will register for the shifts + volunteer_1 = [ + 'Yoshi', "Yoshi", "Turtle", "Mario Land", "Nintendo Land", + "Nintendo State", "Nintendo Nation", "2374983247", + "yoshi@nintendo.com" + ] + volunteer_2 = [ + 'John', "John", "Doe", "7 Alpine Street", "Maplegrove", "Wyoming", + "USA", "23454545", "john@test.com" + ] + volunteer_3 = [ + 'Ash', "Ash", "Ketchum", "Pallet Town", "Kanto", "Gameboy", + "Japan", "23454545", "ash@pikachu.com" + ] + + cls.v1 = create_volunteer_with_details(volunteer_1) + cls.v2 = create_volunteer_with_details(volunteer_2) + cls.v3 = create_volunteer_with_details(volunteer_3) + + @classmethod + def setUpClass(cls): + cls.setup_test_data() + + def tearDown(self): + # remove all registered volunteers + VolunteerShift.objects.all().delete() + + def test_get_shifts_with_open_slots_for_volunteer(self): + """ Uses volunteer v1, v2 """ + + register(self.v1.id, self.s2.id) + register(self.v2.id, self.s1.id) + + open_slots_1 = get_shifts_with_open_slots_for_volunteer( + self.j1.id, self.v1.id) + open_slots_2 = get_shifts_with_open_slots_for_volunteer( + self.j2.id, self.v1.id) + + self.assertIsNotNone(open_slots_1) + self.assertIsNotNone(open_slots_2) + self.assertEqual(len(open_slots_1), 0) + self.assertEqual(len(open_slots_2), 1) + + self.assertEqual(self.s3.id, open_slots_2[0]["id"]) + + def test_get_volunteer_report(self): + + # register volunteer for 2 shifts, log hours for one + register(self.v1.id, self.s1.id) + register(self.v1.id, self.s3.id) + + start_time = datetime.time(hour=9, minute=0) + end_time = datetime.time(hour=10, minute=0) + add_shift_hours(self.v1.id, self.s1.id, start_time, end_time) + + report_1 = get_volunteer_report(self.v1.id, self.e1.name, self.j1.name, + "2012-10-22", "2012-10-30") + report_2 = get_volunteer_report(self.v1.id, self.e1.name, self.j2.name, + "2012-9-1", "2012-10-26") + + # verify that report for logged shift appears + self.assertEqual(len(report_1), 1) + self.assertEqual(len(report_2), 0) + self.assertEqual(self.e1.name, report_1[0]["event_name"]) + self.assertEqual(self.j1.name, report_1[0]["job_name"]) + + # commented out due to bug #327 + # self.assertEqual(start_time, report_1[0]["logged_start_time"]) + # self.assertEqual(end_time, report_1[0]["logged_end_time"]) + # self.assertEqual(1.0, report_1[0]["duration"]) + + def test_get_administrator_report(self): + + register(self.v1.id, self.s1.id) + register(self.v2.id, self.s3.id) + + start_time = datetime.time(hour=11, minute=0) + end_time = datetime.time(hour=12, minute=0) + add_shift_hours(self.v1.id, self.s1.id, start_time, end_time) + add_shift_hours(self.v2.id, self.s3.id, start_time, end_time) + + report_1 = get_administrator_report(self.v1.first_name, "", "", + self.e1.name, self.j1.name, + "2012-10-22", "2012-10-30") + report_2 = get_administrator_report(self.v1.first_name, "", "", + self.e1.name, self.j2.name, + "2012-9-1", "2012-10-26") + report_3 = get_administrator_report("", "", "", self.e1.name, + self.j2.name, "", "") + + # verify that report for logged shift appears + self.assertEqual(len(report_1), 1) + self.assertEqual(len(report_2), 0) + self.assertEqual(len(report_3), 1) + self.assertEqual(self.v1.first_name, report_1[0]["first_name"]) + self.assertEqual(self.v2.first_name, report_3[0]["first_name"]) + + # commented out due to bug #327 + # self.assertEqual(start_time, report_1[0]["logged_start_time"]) + # self.assertEqual(start_time, report_3[0]["logged_start_time"]) + # self.assertEqual(end_time, report_1[0]["logged_end_time"]) + # self.assertEqual(end_time, report_3[0]["logged_end_time"]) + # self.assertEqual(1.0, report_1[0]["duration"]) + # self.assertEqual(1.0, report_3[0]["duration"]) + + def test_add_shift_hours(self): + """ Uses shifts s1, s2, s3 and volunteers v1,v2,v3 """ + + # register will return an exception on error + # (such as when invalid parameters are passed) + # if an exception does get raised, this test will automatically fail + register(self.v1.id, self.s1.id) + self.assertIsNotNone( + VolunteerShift.objects.get( + volunteer_id=self.v1.id, shift_id=self.s1.id)) + + register(self.v1.id, self.s2.id) + self.assertIsNotNone( + VolunteerShift.objects.get( + volunteer_id=self.v1.id, shift_id=self.s2.id)) + + register(self.v1.id, self.s3.id) + self.assertIsNotNone( + VolunteerShift.objects.get( + volunteer_id=self.v1.id, shift_id=self.s3.id)) + + start_time = datetime.time(hour=9, minute=0) + end_time = datetime.time(hour=10, minute=0) + add_shift_hours(self.v1.id, self.s1.id, start_time, end_time) + volunteer_shift = VolunteerShift.objects.get( + volunteer_id=self.v1.id, shift_id=self.s1.id) + self.assertEqual(volunteer_shift.start_time, start_time) + self.assertEqual(volunteer_shift.end_time, end_time) + + start_time = datetime.time(hour=10, minute=0) + end_time = datetime.time(hour=12, minute=0) + add_shift_hours(self.v1.id, self.s2.id, start_time, end_time) + volunteer_shift = VolunteerShift.objects.get( + volunteer_id=self.v1.id, shift_id=self.s2.id) + self.assertEqual(volunteer_shift.start_time, start_time) + self.assertEqual(volunteer_shift.end_time, end_time) + + start_time = datetime.time(hour=5, minute=0) + end_time = datetime.time(hour=6, minute=0) + add_shift_hours(self.v1.id, self.s3.id, start_time, end_time) + volunteer_shift = VolunteerShift.objects.get( + volunteer_id=self.v1.id, shift_id=self.s3.id) + self.assertEqual(volunteer_shift.start_time, start_time) + self.assertEqual(volunteer_shift.end_time, end_time) + + def test_cancel_shift_registration(self): + """ Uses shifts s1, s2, s3 and volunteers v1,v2 """ + + # test cases when try to cancel when they aren't signed up for a shift + with self.assertRaises(ObjectDoesNotExist): + cancel_shift_registration(self.v1.id, self.s1.id) + + with self.assertRaises(ObjectDoesNotExist): + cancel_shift_registration(self.v1.id, self.s2.id) + + with self.assertRaises(ObjectDoesNotExist): + cancel_shift_registration(self.v2.id, self.s1.id) + + # register volunteers to shifts + register(self.v1.id, self.s1.id) + register(self.v2.id, self.s1.id) + register(self.v2.id, self.s2.id) + + # test typical cases + cancel_shift_registration(self.v1.id, self.s1.id) + + with self.assertRaises(ObjectDoesNotExist): + cancel_shift_registration(self.v2.id, self.s1.id) + + cancel_shift_registration(self.v2.id, self.s2.id) + + def test_clear_shift_hours(self): + """ Uses shifts s1, s2, s3 and volunteer v1 """ + + register(self.v1.id, self.s1.id) + self.assertIsNotNone( + VolunteerShift.objects.get( + volunteer_id=self.v1.id, shift_id=self.s1.id)) + + register(self.v1.id, self.s2.id) + self.assertIsNotNone( + VolunteerShift.objects.get( + volunteer_id=self.v1.id, shift_id=self.s2.id)) + + register(self.v1.id, self.s3.id) + self.assertIsNotNone( + VolunteerShift.objects.get( + volunteer_id=self.v1.id, shift_id=self.s3.id)) + + start_time = datetime.time(hour=9, minute=0) + end_time = datetime.time(hour=10, minute=0) + add_shift_hours(self.v1.id, self.s1.id, start_time, end_time) + + start_time = datetime.time(hour=10, minute=0) + end_time = datetime.time(hour=12, minute=0) + add_shift_hours(self.v1.id, self.s2.id, start_time, end_time) + + start_time = datetime.time(hour=5, minute=0) + end_time = datetime.time(hour=6, minute=0) + add_shift_hours(self.v1.id, self.s3.id, start_time, end_time) + + clear_shift_hours(self.v1.id, self.s1.id) + volunteer_shift = VolunteerShift.objects.get( + volunteer_id=self.v1.id, shift_id=self.s1.id) + self.assertIsNone(volunteer_shift.start_time) + self.assertIsNone(volunteer_shift.end_time) + + clear_shift_hours(self.v1.id, self.s2.id) + volunteer_shift = VolunteerShift.objects.get( + volunteer_id=self.v1.id, shift_id=self.s2.id) + self.assertIsNone(volunteer_shift.start_time) + self.assertIsNone(volunteer_shift.end_time) + + clear_shift_hours(self.v1.id, self.s3.id) + volunteer_shift = VolunteerShift.objects.get( + volunteer_id=self.v1.id, shift_id=self.s3.id) + self.assertIsNone(volunteer_shift.start_time) + self.assertIsNone(volunteer_shift.end_time) + + def test_edit_shift_hours(self): + """ Uses shift s1 and volunteer v1 """ + + register(self.v1.id, self.s1.id) + self.assertIsNotNone( + VolunteerShift.objects.get( + volunteer_id=self.v1.id, shift_id=self.s1.id)) + + start_time = datetime.time(hour=9, minute=0) + end_time = datetime.time(hour=10, minute=0) + add_shift_hours(self.v1.id, self.s1.id, start_time, end_time) + + start_time = datetime.time(hour=10, minute=0) + end_time = datetime.time(hour=11, minute=0) + edit_shift_hours(self.v1.id, self.s1.id, start_time, end_time) + volunteer_shift = VolunteerShift.objects.get( + volunteer_id=self.v1.id, shift_id=self.s1.id) + self.assertIsNotNone(volunteer_shift.start_time) + self.assertIsNotNone(volunteer_shift.end_time) + self.assertEqual(volunteer_shift.start_time, start_time) + self.assertEqual(volunteer_shift.end_time, end_time) + + start_time = datetime.time(hour=1, minute=0) + end_time = datetime.time(hour=4, minute=0) + edit_shift_hours(self.v1.id, self.s1.id, start_time, end_time) + volunteer_shift = VolunteerShift.objects.get( + volunteer_id=self.v1.id, shift_id=self.s1.id) + self.assertIsNotNone(volunteer_shift.start_time) + self.assertIsNotNone(volunteer_shift.end_time) + self.assertEqual(volunteer_shift.start_time, start_time) + self.assertEqual(volunteer_shift.end_time, end_time) + + start_time = datetime.time(hour=4, minute=15) + end_time = datetime.time(hour=12, minute=35) + edit_shift_hours(self.v1.id, self.s1.id, start_time, end_time) + volunteer_shift = VolunteerShift.objects.get( + volunteer_id=self.v1.id, shift_id=self.s1.id) + self.assertIsNotNone(volunteer_shift.start_time) + self.assertIsNotNone(volunteer_shift.end_time) + self.assertEqual(volunteer_shift.start_time, start_time) + self.assertEqual(volunteer_shift.end_time, end_time) + + start_time = datetime.time(hour=2, minute=5) + end_time = datetime.time(hour=4, minute=15) + edit_shift_hours(self.v1.id, self.s1.id, start_time, end_time) + volunteer_shift = VolunteerShift.objects.get( + volunteer_id=self.v1.id, shift_id=self.s1.id) + self.assertIsNotNone(volunteer_shift.start_time) + self.assertIsNotNone(volunteer_shift.end_time) + self.assertEqual(volunteer_shift.start_time, start_time) + self.assertEqual(volunteer_shift.end_time, end_time) + + start_time = datetime.time(hour=5, minute=0) + end_time = datetime.time(hour=5, minute=30) + edit_shift_hours(self.v1.id, self.s1.id, start_time, end_time) + volunteer_shift = VolunteerShift.objects.get( + volunteer_id=self.v1.id, shift_id=self.s1.id) + self.assertIsNotNone(volunteer_shift.start_time) + self.assertIsNotNone(volunteer_shift.end_time) + self.assertEqual(volunteer_shift.start_time, start_time) + self.assertEqual(volunteer_shift.end_time, end_time) + + def test_generate_report(self): + """ Uses shifts s1, s2 and volunteer v1 + Tests test_generate_report(volunteer_shift_list) """ + + # register will return an exception on error + # (such as when invalid parameters are passed) + # if an exception does get raised, this test will automatically fail + start_time = datetime.time(hour=9, minute=0) + end_time = datetime.time(hour=10, minute=0) + register(self.v1.id, self.s1.id) + add_shift_hours(self.v1.id, self.s1.id, start_time, end_time) + volunteer_shift_1 = VolunteerShift.objects.get( + volunteer_id=self.v1.id, shift_id=self.s1.id) + self.assertIsNotNone(volunteer_shift_1) + + register(self.v1.id, self.s2.id) + add_shift_hours(self.v1.id, self.s2.id, start_time, end_time) + volunteer_shift_2 = VolunteerShift.objects.get( + volunteer_id=self.v1.id, shift_id=self.s2.id) + self.assertIsNotNone(volunteer_shift_2) + + volunteer_shift_list = [volunteer_shift_1, volunteer_shift_2] + + reports = generate_report(volunteer_shift_list) + self.assertEqual(len(reports), 2) + self.assertIsNotNone(reports) + + def test_get_all_volunteer_shifts_with_hours(self): + # Test get_all_volunteer_shifts_with_hours() + register(self.v1.id, self.s1.id) + register(self.v2.id, self.s2.id) + + start_time = datetime.time(hour=9, minute=0) + end_time = datetime.time(hour=10, minute=0) + + add_shift_hours(self.v1.id, self.s1.id, start_time, end_time) + hours_list = get_all_volunteer_shifts_with_hours() + + self.assertEqual(len(hours_list), 1) + self.assertEqual(self.v1.id, hours_list[0].volunteer_id) + self.assertEqual(self.s1.id, hours_list[0].shift_id) + + self.assertIsNotNone(get_all_volunteer_shifts_with_hours()) + + def test_get_shift_slots_remaining(self): + """ Uses shifts s1, s2, s3 + Tests get_shift_slots_remaining(s_id) """ + + register(self.v1.id, self.s1.id) + register(self.v2.id, self.s3.id) + register(self.v3.id, self.s3.id) + + slots_s1 = get_shift_slots_remaining(self.s1.id) + slots_s2 = get_shift_slots_remaining(self.s2.id) + slots_s3 = get_shift_slots_remaining(self.s3.id) + + self.assertIsNotNone(slots_s1) + self.assertIsNotNone(slots_s2) + self.assertIsNotNone(slots_s3) + + self.assertEqual(slots_s1, 0) + self.assertEqual(slots_s2, 2) + self.assertEqual(slots_s3, 2) + + def test_get_shifts_with_open_slots(self): + """ Uses jobs j1, j2 + Tests get_shifts_with_open_slots(j_id) """ + + register(self.v1.id, self.s1.id) + register(self.v2.id, self.s3.id) + + shift_list_1 = get_shifts_with_open_slots(self.j1.id) + shift_list_2 = get_shifts_with_open_slots(self.j2.id) + + self.assertIsNotNone(shift_list_1) + self.assertIsNotNone(shift_list_2) + self.assertEqual(len(shift_list_1), 1) + self.assertEqual(len(shift_list_2), 1) + + self.assertNotEqual(self.s1.id, shift_list_1[0]["id"]) + self.assertEqual(self.s2.id, shift_list_1[0]["id"]) + self.assertEqual(self.s3.id, shift_list_2[0]["id"]) + + def test_get_unlogged_shifts_by_volunteer_id(self): + """ Uses shifts s1, s2 and volunteer v1 """ + + # sign up + register(self.v1.id, self.s1.id) + register(self.v1.id, self.s2.id) + + start_time = datetime.time(hour=9, minute=0) + end_time = datetime.time(hour=10, minute=0) + + add_shift_hours(self.v1.id, self.s1.id, start_time, end_time) + + # test typical case + shift_list = get_unlogged_shifts_by_volunteer_id(self.v1.id) + self.assertIsNotNone(shift_list) + self.assertNotEqual(shift_list, False) + self.assertEqual(len(shift_list), 1) + self.assertNotIn(self.s1, shift_list) + self.assertIn(self.s2, shift_list) + self.assertNotIn(self.s3, shift_list) + + def test_get_volunteer_shift_by_id(self): + """ Uses shifts s1,s2,s3 and volunteers v1,v2""" + + # test cases where signed up + register(self.v1.id, self.s1.id) + register(self.v1.id, self.s2.id) + register(self.v1.id, self.s3.id) + + register(self.v2.id, self.s1.id) + register(self.v2.id, self.s2.id) + register(self.v2.id, self.s3.id) + + self.assertEqual( + get_volunteer_shift_by_id(self.v1.id, self.s1.id), + VolunteerShift.objects.get( + volunteer_id=self.v1.id, shift_id=self.s1.id)) + self.assertEqual( + get_volunteer_shift_by_id(self.v1.id, self.s2.id), + VolunteerShift.objects.get( + volunteer_id=self.v1.id, shift_id=self.s2.id)) + self.assertEqual( + get_volunteer_shift_by_id(self.v1.id, self.s3.id), + VolunteerShift.objects.get( + volunteer_id=self.v1.id, shift_id=self.s3.id)) + + # self.assertEqual(get_volunteer_shift_by_id(v2.id, s1.id), + # VolunteerShift.objects.get(volunteer_id=v2.id, shift_id=s1.id)) + # why does this throw DoesNotExist? + self.assertEqual( + get_volunteer_shift_by_id(self.v2.id, self.s2.id), + VolunteerShift.objects.get( + volunteer_id=self.v2.id, shift_id=self.s2.id)) + self.assertEqual( + get_volunteer_shift_by_id(self.v2.id, self.s3.id), + VolunteerShift.objects.get( + volunteer_id=self.v2.id, shift_id=self.s3.id)) + + def test_get_volunteer_shifts_with_hours(self): + """ Uses volunteers v1 and v2 + Test get_volunteer_shifts_with_hours(v_id) """ + + register(self.v1.id, self.s1.id) + register(self.v1.id, self.s2.id) + + start_time = datetime.time(hour=9, minute=0) + end_time = datetime.time(hour=10, minute=0) + + add_shift_hours(self.v1.id, self.s1.id, start_time, end_time) + + v1_hours = get_volunteer_shifts_with_hours(self.v1) + v2_hours = get_volunteer_shifts_with_hours(self.v2) + + self.assertIsNotNone(get_volunteer_shifts_with_hours(self.v1)) + self.assertIsNotNone(get_volunteer_shifts_with_hours(self.v2)) + + self.assertEqual(len(v1_hours), 1) + self.assertEqual(self.s1.id, v1_hours[0].shift_id) + self.assertEqual(len(v2_hours), 0) + + def test_get_volunteers_by_shift_id(self): + """ Uses volunteers v1,v2,v3 and shifts s1,s2,s3 """ + + # sign up + register(self.v3.id, self.s1.id) + register(self.v1.id, self.s1.id) + register(self.v1.id, self.s3.id) + register(self.v3.id, self.s3.id) + register(self.v2.id, self.s3.id) + + # get volunteer lists + volunteer_list_for_shift_1 = get_volunteers_by_shift_id(self.s1.id) + volunteer_list_for_shift_2 = get_volunteers_by_shift_id(self.s2.id) + volunteer_list_for_shift_3 = get_volunteers_by_shift_id(self.s3.id) + + # test typical case + self.assertEqual(len(volunteer_list_for_shift_1), 1) + self.assertEqual(len(volunteer_list_for_shift_2), 0) + self.assertEqual(len(volunteer_list_for_shift_3), 3) + + self.assertIn(self.v3, volunteer_list_for_shift_1) + self.assertNotIn(self.v1, volunteer_list_for_shift_1) + self.assertIn(self.v1, volunteer_list_for_shift_3) + self.assertIn(self.v2, volunteer_list_for_shift_3) + self.assertIn(self.v3, volunteer_list_for_shift_3) + + # test order + self.assertEqual(volunteer_list_for_shift_3[0], self.v3) + self.assertEqual(volunteer_list_for_shift_3[1], self.v2) + self.assertEqual(volunteer_list_for_shift_3[2], self.v1) + + def test_get_logged_volunteers_by_shift_id(self): + """ Uses volunteers v1,v2,v3 and shift s3 """ + + # sign up + register(self.v3.id, self.s3.id) + register(self.v1.id, self.s3.id) + register(self.v2.id, self.s3.id) + + start_time = datetime.time(hour=1, minute=0) + end_time = datetime.time(hour=2, minute=0) + add_shift_hours(self.v1.id, self.s3.id, start_time, end_time) + + start_time = datetime.time(hour=2, minute=0) + end_time = datetime.time(hour=3, minute=0) + add_shift_hours(self.v3.id, self.s3.id, start_time, end_time) + + # get volunteer list + logged_volunteer_list_for_shift = get_logged_volunteers_by_shift_id( + self.s3.id) + + # test typical case and order + self.assertEqual(len(logged_volunteer_list_for_shift), 2) + self.assertEqual(logged_volunteer_list_for_shift[0].volunteer, self.v3) + self.assertEqual(logged_volunteer_list_for_shift[1].volunteer, self.v1) + + def test_is_signed_up(self): + """ Uses volunteers v1,v2 and shifts s1,s2,s3 """ + + # test cases where not signed up yet + self.assertFalse(is_signed_up(self.v1.id, self.s1.id)) + self.assertFalse(is_signed_up(self.v1.id, self.s2.id)) + self.assertFalse(is_signed_up(self.v1.id, self.s3.id)) + + # test cases where signed up + register(self.v1.id, self.s1.id) + register(self.v1.id, self.s2.id) + register(self.v1.id, self.s3.id) + + self.assertTrue(is_signed_up(self.v1.id, self.s1.id)) + self.assertTrue(is_signed_up(self.v1.id, self.s2.id)) + self.assertTrue(is_signed_up(self.v1.id, self.s3.id)) + + # test case where more than one volunteer signs up for the same shift + self.assertFalse(is_signed_up(self.v2.id, self.s1.id)) + self.assertFalse(is_signed_up(self.v2.id, self.s2.id)) + self.assertFalse(is_signed_up(self.v2.id, self.s3.id)) + + register(self.v2.id, self.s2.id) + register(self.v2.id, self.s3.id) + + self.assertFalse(is_signed_up(self.v2.id, self.s1.id)) + self.assertTrue(is_signed_up(self.v2.id, self.s2.id)) + self.assertTrue(is_signed_up(self.v2.id, self.s3.id)) + + def test_register(self): + """ Uses volunteers v1,v2 and shifts s1,s2,s3 """ + + ERROR_CODE_ALREADY_SIGNED_UP = "ERROR_CODE_ALREADY_SIGNED_UP" + ERROR_CODE_NO_SLOTS_REMAINING = "ERROR_CODE_NO_SLOTS_REMAINING" + + # test typical cases + register(self.v1.id, self.s1.id) + self.assertIsNotNone( + VolunteerShift.objects.get( + volunteer_id=self.v1.id, shift_id=self.s1.id)) + + register(self.v1.id, self.s2.id) + self.assertIsNotNone( + VolunteerShift.objects.get( + volunteer_id=self.v1.id, shift_id=self.s2.id)) + + register(self.v1.id, self.s3.id) + self.assertIsNotNone( + VolunteerShift.objects.get( + volunteer_id=self.v1.id, shift_id=self.s3.id)) + + # test cases where volunteer tries to sign up for a shift + # they are already signed up for + self.assertEqual( + register(self.v1.id, self.s1.id), ERROR_CODE_ALREADY_SIGNED_UP) + self.assertEqual( + register(self.v1.id, self.s2.id), ERROR_CODE_ALREADY_SIGNED_UP) + self.assertEqual( + register(self.v1.id, self.s3.id), ERROR_CODE_ALREADY_SIGNED_UP) + + # test case where more than one volunteer signs up for the same shift + # v2 can't sign up for s1 because there are no slots remaining + self.assertEqual( + register(self.v2.id, self.s1.id), ERROR_CODE_NO_SLOTS_REMAINING) + + register(self.v2.id, self.s2.id) + self.assertIsNotNone( + VolunteerShift.objects.get( + volunteer_id=self.v2.id, shift_id=self.s2.id)) + + register(self.v2.id, self.s3.id) + self.assertIsNotNone( + VolunteerShift.objects.get( + volunteer_id=self.v2.id, shift_id=self.s3.id)) + + # test cases where a volunteer tries to sign up for a shift + # they are already signed up for + self.assertEqual( + register(self.v2.id, self.s2.id), ERROR_CODE_ALREADY_SIGNED_UP) + self.assertEqual( + register(self.v2.id, self.s3.id), ERROR_CODE_ALREADY_SIGNED_UP) + + +class ShiftReminderTest(unittest.TestCase): + @classmethod + def setup_test_data(cls): + + cls.e1 = e1 + cls.j1 = j1 + cls.j2 = j2 + + shift_1 = ["2015-08-23", "9:00", "15:00", 1, cls.j1] + shift_2 = [date.today() + timedelta(7), "10:00", "16:00", 2, + cls.j1] # one week date + shift_3 = [date.today() + timedelta(1), "12:00", "18:00", 2, + cls.j2] # tomorrow date + + cls.s1 = create_shift_with_details(shift_1) + cls.s2 = create_shift_with_details(shift_2) + cls.s3 = create_shift_with_details(shift_3) + + volunteer_1 = [ + 'Jake', "Jake", "Flamoy", "Mario Land", "Nintendo Land", + "Nintendo State", "Nintendo Nation", "2374983247", + "jake@nintendo.com" + ] + volunteer_2 = [ + 'Dora', "Dorothy", "Flamoy", "7 Alpine Street", "Maplegrove", + "Wyoming", "USA", "23454545", "dora@test.com" + ] + + cls.v1 = create_volunteer_with_details(volunteer_1) + cls.v2 = create_volunteer_with_details(volunteer_2) + + @classmethod + def setUpClass(cls): + cls.setup_test_data() + + @classmethod + def tearDownClass(cls): + cls.s1.delete() + cls.s2.delete() + cls.s3.delete() + + # remove all registered volunteers + VolunteerShift.objects.all().delete() + + def test_send_reminder(self): + + location = [ + "Test address", "Atlanta", "Georgia", "USA", + "Near the south entrance" + ] + + set_shift_location(self.s1, location) + set_shift_location(self.s2, location) + set_shift_location(self.s3, location) + + self.v1.reminder_days = 1 + self.v2.reminder_days = 7 + self.v1.save() + self.v2.save() + + # sign up + register(self.v1.id, self.s1.id) + register(self.v1.id, self.s2.id) + register(self.v1.id, self.s3.id) + register(self.v2.id, self.s1.id) + register(self.v2.id, self.s2.id) + register(self.v2.id, self.s3.id) + + # test typical case + result = send_reminder() + + self.assertEqual(result, 2) + + +class DeleteShiftTest(unittest.TestCase): + @classmethod + def setup_test_data(cls): + + cls.e1 = e1 + cls.j1 = j1 + + shift_1 = ["2012-10-28", "9:00", "15:00", 1, cls.j1] + shift_2 = ["2012-10-25", "10:00", "16:00", 2, cls.j1] + + cls.s1 = create_shift_with_details(shift_1) + cls.s2 = create_shift_with_details(shift_2) + + volunteer_1 = [ + 'Aaron', "Aaron", "Turtle", "Mario Land", "Nintendo Land", + "Nintendo State", "Nintendo Nation", "2374983247", + "aaron@nintendo.com" + ] + cls.v1 = create_volunteer_with_details(volunteer_1) + + @classmethod + def setUpClass(cls): + cls.setup_test_data() + + @classmethod + def tearDownClass(cls): + cls.s2.delete() + + # remove all registered volunteers + VolunteerShift.objects.all().delete() + + def test_delete_shift(self): + # Test delete_shift(shift_id) + + self.assertTrue(delete_shift(self.s1.id)) + self.assertFalse(delete_shift(1000)) + + register(self.v1.id, self.s2.id) + self.assertFalse(delete_shift(self.s2.id)) diff --git a/vms/shift/tests/test_shiftDetails.py b/vms/shift/tests/test_shiftDetails.py index 19502e1..d35eb6c 100644 --- a/vms/shift/tests/test_shiftDetails.py +++ b/vms/shift/tests/test_shiftDetails.py @@ -1,6 +1,8 @@ # third party from selenium import webdriver -from selenium.common.exceptions import NoSuchElementException +from selenium.webdriver.support.ui import WebDriverWait +from selenium.webdriver.support import expected_conditions as EC +from selenium.webdriver.common.by import By # Django from django.contrib.staticfiles.testing import LiveServerTestCase @@ -8,30 +10,31 @@ # local Django from pom.pages.authenticationPage import AuthenticationPage from pom.pages.shiftDetailsPage import ShiftDetailsPage -# from shift.models import VolunteerShift from shift.utils import (create_volunteer_with_details, create_admin, create_event_with_details, create_job_with_details, create_shift_with_details, log_hours_with_details, register_volunteer_for_shift_utility) -# Class contains failing test cases which have been documented -# Test class commented out to prevent travis build failure -""" - + class ShiftDetails(LiveServerTestCase): - ''' + """ Contains Tests for View Shift Details Page Status of shift page is checked for following cases - - No Volunteer is registered - Volunteer registered but no hours logged - Volunteer with logged shift hours - ''' + """ @classmethod def setUpClass(cls): + """Method to initiate class level objects. + + This method initiates Firefox WebDriver, WebDriverWait and + the corresponding POM objects for this Test Class + """ cls.volunteer_detail = [ - 'volunteer-usernameq', 'Michael', 'Reed', 'address', 'city', + 'volunteer-username', 'Michael', 'Reed', 'address', 'city', 'state', 'country', '9999999999', 'volunteer@volunteer.com', 'organization' ] @@ -41,58 +44,106 @@ def setUpClass(cls): cls.driver.maximize_window() cls.shift_details_page = ShiftDetailsPage(cls.driver) cls.authentication_page = AuthenticationPage(cls.driver) + cls.wait = WebDriverWait(cls.driver, 10) super(ShiftDetails, cls).setUpClass() def setUp(self): + """ + Method consists of statements to be executed before + start of each test. + """ self.admin = create_admin() self.login_admin() - self.shift = self.register_dataset() + self.shift = ShiftDetails.register_dataset() def tearDown(self): - pass + """ + Method consists of statements to be executed at + end of each test. + """ + self.authentication_page.logout() @classmethod def tearDownClass(cls): + """ + Class method to quit the Firefox WebDriver session after + execution of all tests in class. + """ cls.driver.quit() super(ShiftDetails, cls).tearDownClass() def login_admin(self): + """ + Utility function to login as administrator. + """ authentication_page = self.authentication_page authentication_page.server_url = self.live_server_url - authentication_page.login({'username': 'admin', 'password': 'admin'}) - - def register_dataset(self): - e1 = create_event_with_details(['event', '2017-06-15', '2017-06-17']) + authentication_page.login({ + 'username': 'admin', + 'password': 'admin' + }) + + @staticmethod + def register_dataset(): + """ + Utility function to create data for testing + :return: Shift type of object. + """ + e1 = create_event_with_details(['event', '2050-06-15', '2050-06-17']) j1 = create_job_with_details( - ['job', '2017-06-15', '2017-06-15', 'job description', e1]) + ['job', '2050-06-15', '2050-06-15', 'job description', e1]) s1 = create_shift_with_details( - ['2017-06-15', '09:00', '15:00', '6', j1]) + ['2050-06-15', '09:00', '15:00', '6', j1]) return s1 + def wait_for_home_page(self): + """ + Utility function to perform explicit wait for home page. + """ + self.wait.until( + EC.presence_of_element_located( + (By.XPATH, + "//h1[contains(text(), 'Volunteer Management System')]" + ) + ) + ) + def test_view_with_unregistered_volunteers(self): + """ + Test display of shift details with no registered volunteer. + """ shift_details_page = self.shift_details_page shift_details_page.live_server_url = self.live_server_url + + self.wait_for_home_page() + shift_details_page.navigate_to_shift_details_view() - # verify details and slots remaining + # Verify details and slots remaining self.assertEqual(shift_details_page.get_shift_job(), 'job') - self.assertEqual(shift_details_page.get_shift_date(), 'June 15, 2017') + self.assertEqual(shift_details_page.get_shift_date(), 'June 15, 2050') self.assertEqual(shift_details_page.get_max_shift_volunteer(), '6') self.assertEqual(shift_details_page.get_shift_start_time(), '9 a.m.') self.assertEqual(shift_details_page.get_shift_end_time(), '3 p.m.') - # verify that there are no registered shifts or logged hours - self.assertEqual(shift_details_page.get_message_box( - ), 'There are currently no volunteers assigned to this shift. Please assign volunteers to view more details' + # Verify that there are no registered shifts or logged hours + self.assertEqual(shift_details_page.get_message_box(), + 'There are currently no volunteers assigned to this shift. ' + 'Please assign volunteers to view more details' ) def test_view_with_only_registered_volunteers(self): - + """ + Test display of shift details with registered volunteer. + """ shift_details_page = self.shift_details_page shift_details_page.live_server_url = self.live_server_url volunteer = create_volunteer_with_details(self.volunteer_detail) volunteer_shift = register_volunteer_for_shift_utility( self.shift, volunteer) + + self.wait_for_home_page() + shift_details_page.navigate_to_shift_details_view() # verify that the shift slot is decreased by 1 @@ -100,20 +151,22 @@ def test_view_with_only_registered_volunteers(self): self.assertEqual(shift_details_page.get_max_shift_volunteer(), '5') # verify that assigned volunteers shows up but no logged hours yet - self.assertEqual( - len(shift_details_page.get_registered_volunteers()), 1) - self.assertEqual(shift_details_page.get_registered_volunteer_name(), - 'Michael') - self.assertEqual(shift_details_page.get_registered_volunteer_email(), - 'volunteer@volunteer.com') - self.assertEqual(shift_details_page.get_message_box(), - 'There are no logged hours at the moment') + self.assertEqual(len(shift_details_page.get_registered_volunteers()), 1) + self.assertEqual(shift_details_page.get_registered_volunteer_name(), 'Michael') + self.assertEqual(shift_details_page.get_registered_volunteer_email(), 'volunteer@volunteer.com') + self.assertEqual(shift_details_page.get_message_box(), 'There are no logged hours at the moment') def test_view_with_logged_hours(self): + """ + Test display of shift details with hours logged in the shift. + """ shift_details_page = self.shift_details_page shift_details_page.live_server_url = self.live_server_url volunteer = create_volunteer_with_details(self.volunteer_detail) log_hours_with_details(volunteer, self.shift, '13:00', '14:00') + + self.wait_for_home_page() + shift_details_page.navigate_to_shift_details_view() # verify that the shift slot is decreased by 1 @@ -121,15 +174,11 @@ def test_view_with_logged_hours(self): self.assertEqual(shift_details_page.get_max_shift_volunteer(), '5') # verify that assigned volunteers shows up - self.assertEqual( - len(shift_details_page.get_registered_volunteers()), 1) - self.assertEqual(shift_details_page.get_registered_volunteer_email(), - 'volunteer@volunteer.com') + self.assertEqual(len(shift_details_page.get_registered_volunteers()), 1) + self.assertEqual(shift_details_page.get_registered_volunteer_email(), 'volunteer@volunteer.com') # verify that hours are logged by volunteer self.assertEqual(len(shift_details_page.get_logged_volunteers()), 1) - self.assertEqual(shift_details_page.get_logged_volunteer_name(), - 'Michael') + self.assertEqual(shift_details_page.get_logged_volunteer_name(), 'Michael') self.assertEqual(shift_details_page.get_logged_start_time(), '1 p.m.') self.assertEqual(shift_details_page.get_logged_end_time(), '2 p.m.') -""" diff --git a/vms/shift/tests/test_shiftHours.py b/vms/shift/tests/test_shiftHours.py index 65f7764..c750c8f 100644 --- a/vms/shift/tests/test_shiftHours.py +++ b/vms/shift/tests/test_shiftHours.py @@ -8,20 +8,28 @@ # local Django from pom.pages.authenticationPage import AuthenticationPage from pom.pages.completedShiftsPage import CompletedShiftsPage -from shift.models import VolunteerShift from shift.utils import (create_volunteer, create_event_with_details, create_job_with_details, create_shift_with_details, log_hours_with_details) -# Class contains failing test cases which have been documented -# Test class commented out to prevent travis build failure -""" + class ShiftHours(LiveServerTestCase): - ''' - ''' + """ + Contains tests for + - Display hours with logged and unlogged shifts. + - Edit hours with valid values. + - Edit hours with end time after start time. + - Edit hours with time outside shift time. + - Cancellation of hours. + """ @classmethod def setUpClass(cls): + """Method to initiate class level objects. + + This method initiates Firefox WebDriver, WebDriverWait and + the corresponding POM objects for this Test Class + """ cls.driver = webdriver.Firefox() cls.driver.implicitly_wait(5) cls.driver.maximize_window() @@ -30,18 +38,33 @@ def setUpClass(cls): super(ShiftHours, cls).setUpClass() def setUp(self): + """ + Method consists of statements to be executed before + start of each test. + """ self.v1 = create_volunteer() self.login_volunteer() def tearDown(self): - pass + """ + Method consists of statements to be executed at + end of each test. + """ + self.authentication_page.logout() @classmethod def tearDownClass(cls): + """ + Class method to quit the Firefox WebDriver session after + execution of all tests in class. + """ cls.driver.quit() super(ShiftHours, cls).tearDownClass() def login_volunteer(self): + """ + Utility function to login as volunteer. + """ self.authentication_page.server_url = self.live_server_url self.authentication_page.login({ 'username': 'volunteer', @@ -49,77 +72,82 @@ def login_volunteer(self): }) def register_dataset(self): - - # create shift and log hours - e1 = create_event_with_details(['event', '2017-06-15', '2017-06-17']) + """ + Utility function to create valid data for test. + """ + # Create shift and log hours + e1 = create_event_with_details( + ['event', '2050-06-15', '2050-06-17'] + ) j1 = create_job_with_details( - ['job', '2017-06-15', '2017-06-15', 'job description', e1]) + ['job', '2050-06-15', '2050-06-15', 'job description', e1] + ) s1 = create_shift_with_details( - ['2017-06-15', '09:00', '15:00', '6', j1]) + ['2050-06-15', '09:00', '15:00', '6', j1] + ) log_hours_with_details(self.v1, s1, '12:00', '13:00') def test_view_with_unlogged_shift(self): + """ + Test display of shift hours with unlogged shifts. + """ completed_shifts_page = self.completed_shifts_page + completed_shifts_page.live_server_url = self.live_server_url completed_shifts_page.go_to_completed_shifts() - self.assertEqual( - self.driver.current_url, self.live_server_url + - completed_shifts_page.view_hours_page + str(self.v1.id)) + self.assertEqual(completed_shifts_page.remove_i18n(self.driver.current_url), + self.live_server_url + completed_shifts_page.view_hours_page + + str(self.v1.id) + ) self.assertEqual(completed_shifts_page.get_info_box(), 'You have not logged any hours.') def test_view_with_logged_shift(self): + """ + Test display of shift hours with logged shifts. + """ self.register_dataset() completed_shifts_page = self.completed_shifts_page completed_shifts_page.go_to_completed_shifts() self.assertEqual(completed_shifts_page.get_shift_job(), 'job') - self.assertEqual(completed_shifts_page.get_shift_date(), - 'June 15, 2017') + self.assertEqual(completed_shifts_page.get_shift_date(), 'June 15, 2050') self.assertEqual(completed_shifts_page.get_shift_start_time(), 'noon') self.assertEqual(completed_shifts_page.get_shift_end_time(), '1 p.m.') - self.assertEqual(completed_shifts_page.get_edit_shift_hours(), - 'Edit Hours') - self.assertEqual(completed_shifts_page.get_clear_shift_hours(), - 'Clear Hours') + self.assertEqual(completed_shifts_page.get_edit_shift_hours(), 'Edit Hours') + self.assertEqual(completed_shifts_page.get_clear_shift_hours(), 'Clear Hours') def test_edit_hours(self): + """ + Test edit of the logged hours. + """ self.register_dataset() completed_shifts_page = self.completed_shifts_page completed_shifts_page.go_to_completed_shifts() completed_shifts_page.edit_hours('10:00', '13:00') - self.assertEqual(completed_shifts_page.get_shift_start_time(), - '10 a.m.') + self.assertEqual(completed_shifts_page.get_shift_start_time(), '10 a.m.') self.assertEqual(completed_shifts_page.get_shift_end_time(), '1 p.m.') - # database check to ensure logged hours are edited - self.assertEqual(len(VolunteerShift.objects.all()), 1) - self.assertNotEqual( - len( - VolunteerShift.objects.filter( - start_time='10:00', end_time='13:00')), 0) - def test_end_hours_less_than_start_hours(self): + """ + Test in edit that end time is after start time. + """ self.register_dataset() completed_shifts_page = self.completed_shifts_page completed_shifts_page.go_to_completed_shifts() completed_shifts_page.edit_hours('14:00', '12:00') - + completed_shifts_page.get_danger_box() try: completed_shifts_page.get_danger_box() except NoSuchElementException: - raise Exception("End hours greater than start hours") - - # database check to ensure logged hours are not edited - self.assertEqual(len(VolunteerShift.objects.all()), 1) - self.assertNotEqual( - len( - VolunteerShift.objects.filter( - start_time='12:00', end_time='13:00')), 0) + raise Exception("End hours should be greater than start hours") def test_logged_hours_between_shift_hours(self): + """ + Test edit of logged hours to time outside the shift. + """ self.register_dataset() completed_shifts_page = self.completed_shifts_page completed_shifts_page.go_to_completed_shifts() @@ -128,32 +156,21 @@ def test_logged_hours_between_shift_hours(self): self.assertEqual(completed_shifts_page.get_danger_box().text, 'Logged hours should be between shift hours') - # database check to ensure logged hours are not edited - self.assertEqual(len(VolunteerShift.objects.all()), 1) - self.assertNotEqual( - len( - VolunteerShift.objects.filter( - start_time='12:00', end_time='13:00')), 0) - def test_cancel_hours(self): + """ + Test clearing of shift hours. + """ self.register_dataset() completed_shifts_page = self.completed_shifts_page completed_shifts_page.go_to_completed_shifts() self.assertEqual(completed_shifts_page.get_shift_job(), 'job') - self.assertEqual(completed_shifts_page.get_clear_shift_hours(), - 'Clear Hours') + self.assertEqual(completed_shifts_page.get_clear_shift_hours(), 'Clear Hours') completed_shifts_page.click_to_clear_hours() - self.assertEqual(completed_shifts_page.get_clear_shift_hours_text(), - 'Clear Shift Hours') + self.assertEqual(completed_shifts_page.get_clear_shift_hours_text(), 'Clear Shift Hours') completed_shifts_page.submit_form() with self.assertRaises(NoSuchElementException): self.assertEqual(completed_shifts_page.get_shift_job(), 'job') - # database check to ensure logged hours are cleared - self.assertEqual(len(VolunteerShift.objects.all()), 1) - self.assertEqual(len(VolunteerShift.objects.filter( - start_time__isnull=False, end_time__isnull=False)), 0) -""" diff --git a/vms/shift/tests/test_unit.py b/vms/shift/tests/test_unit.py index de8d25a..535d742 100644 --- a/vms/shift/tests/test_unit.py +++ b/vms/shift/tests/test_unit.py @@ -1,4 +1,412 @@ +# third party + # Django -# from django.test import TestCase +from django.db.models import Q +from django.test.testcases import TestCase + +# local Django +from shift.models import Shift, VolunteerShift +from shift.utils import create_event_with_details, create_job_with_details, create_shift_with_details, \ + create_volunteer_with_details, register_volunteer_for_shift_utility +from volunteer.models import Volunteer + + +class ShiftModelTests(TestCase): + """ + Contains database tests of Shift model for + - Creation of model with valid and invalid values. + - Edit of model with valid and invalid values. + - Deletion of model + - Model representation + """ + + def setUp(self): + """ + Method consists of statements to be executed before + start of each test. + """ + self.event = ShiftModelTests.create_event() + self.job = self.create_job() + + def tearDown(self): + """ + Method consists of statements to be executed at + end of each test. + """ + pass + + @staticmethod + def create_event(): + """ + Utility function to create a valid event. + :return: Event type object + """ + event = ['event-name', '2050-05-24', '2050-05-28'] + created_event = create_event_with_details(event) + return created_event + + def create_job(self): + """ + Utility function to create a valid job. + :return: Job type object + """ + job = ['job-name', '2050-05-24', '2050-05-28', 'job-description', self.event, + 'dummy description', 'dummy venue'] + created_job = create_job_with_details(job) + return created_job + + def create_valid_shift(self): + """ + Utility function to create a valid shift. + :return: Shift type object + """ + shift = ['2050-05-24', '09:00:00', '12:00:00', '10', self.job] + created_shift = create_shift_with_details(shift) + return created_shift + + def create_invalid_shift(self): + """ + Utility function to create an invalid shift. + :return: Shift type object + """ + shift = ['2050-05-29', '12:00:00', '09:00:00', '10', self.job] + created_shift = create_shift_with_details(shift) + return created_shift + + def test_valid_model_create(self): + """ + Database test for model creation with valid values. + """ + shift = self.create_valid_shift() + + # Check database for shift creation + self.assertEqual(len(Shift.objects.all()), 1) + + shift_in_db = Shift.objects.get(Q(job=self.job)) + # Check correctness + self.assertEqual(str(shift_in_db.date), shift.date) + self.assertEqual(str(shift_in_db.start_time), shift.start_time) + self.assertEqual(str(shift_in_db.end_time), shift.end_time) + self.assertEqual(str(shift_in_db.max_volunteers), shift.max_volunteers) + self.assertEqual(shift_in_db.address, shift.address) + self.assertEqual(shift_in_db.venue, shift.venue) + + def test_invalid_model_create(self): + """ + Database test for model creation with invalid values. + """ + # Can't check unless a clean function is defined in forms. + pass + + def test_model_edit_with_valid_values(self): + """ + Database test for model edit with valid values. + """ + shift = self.create_valid_shift() + + # Check database for shift creation + self.assertEqual(len(Shift.objects.all()), 1) + + shift_in_db = Shift.objects.get(Q(job=self.job)) + # Check correctness + self.assertEqual(str(shift_in_db.date), shift.date) + self.assertEqual(str(shift_in_db.start_time), shift.start_time) + self.assertEqual(str(shift_in_db.end_time), shift.end_time) + self.assertEqual(str(shift_in_db.max_volunteers), shift.max_volunteers) + self.assertEqual(shift_in_db.address, shift.address) + self.assertEqual(shift_in_db.venue, shift.venue) + + shift_in_db.max_volunteers = 11 + shift_in_db.save() + + # Checking no new instance created. + self.assertEqual(len(Shift.objects.all()), 1) + shift_in_db = Shift.objects.get(Q(job=self.job)) + # Check correctness + self.assertEqual(str(shift_in_db.date), shift.date) + self.assertEqual(str(shift_in_db.start_time), shift.start_time) + self.assertEqual(str(shift_in_db.end_time), shift.end_time) + self.assertEqual(str(shift_in_db.max_volunteers), '11') + self.assertEqual(shift_in_db.address, shift.address) + self.assertEqual(shift_in_db.venue, shift.venue) + + def test_model_edit_with_invalid_values(self): + """ + Database test for model edit with invalid values. + """ + shift = self.create_valid_shift() + + # Check database for shift creation + self.assertEqual(len(Shift.objects.all()), 1) + + shift_in_db = Shift.objects.get(Q(job=self.job)) + # Check correctness + self.assertEqual(str(shift_in_db.date), shift.date) + self.assertEqual(str(shift_in_db.start_time), shift.start_time) + self.assertEqual(str(shift_in_db.end_time), shift.end_time) + self.assertEqual(str(shift_in_db.max_volunteers), shift.max_volunteers) + + # Can't check unless a clean function is defined in forms. + + def test_model_delete(self): + """ + Database test for model deletion. + """ + shift = self.create_valid_shift() + + # Check database for shift creation + self.assertEqual(len(Shift.objects.all()), 1) + + shift_in_db = Shift.objects.get(Q(job=self.job)) + # Check correctness + self.assertEqual(str(shift_in_db.date), shift.date) + self.assertEqual(str(shift_in_db.start_time), shift.start_time) + self.assertEqual(str(shift_in_db.end_time), shift.end_time) + self.assertEqual(str(shift_in_db.max_volunteers), shift.max_volunteers) + + shift_in_db.delete() + + # Check instance deletion. + self.assertEqual(len(Shift.objects.all()), 0) + + def test_model_representation(self): + """ + Database test for model representation. + """ + shift = self.create_valid_shift() + + # Check database for shift creation + self.assertEqual(len(Shift.objects.all()), 1) + + shift_in_db = Shift.objects.get(Q(job=self.job)) + # Check correctness + self.assertEqual(str(shift_in_db), 'job-name - 2050-05-24') + + +class VolunteerShiftModelTests(TestCase): + """ + Contains database tests of VolunteerShift model for + - Creation of model with valid and invalid values. + - Edit of model with valid and invalid values. + - Deletion of model + - Model representation + """ + def setUp(self): + """ + Method consists of statements to be executed before + start of each test. + """ + self.event = self.create_event() + self.job = self.create_job() + + def tearDown(self): + """ + Method consists of statements to be executed at + end of each test. + """ + pass + + @staticmethod + def create_event(): + """ + Utility function to create a valid event. + :return: Event type object + """ + event = ['event-name', '2050-05-24', '2050-05-28'] + created_event = create_event_with_details(event) + return created_event + + def create_job(self): + """ + Utility function to create a valid job. + :return: Job type object + """ + job = ['job-name', '2050-05-24', '2050-05-28', 'job-description', self.event] + created_job = create_job_with_details(job) + return created_job + + def create_shift(self): + """ + Utility function to create a valid shift. + :return: Shift type object + """ + shift = ['2050-05-24', '09:00:00', '12:00:00', '10', self.job] + created_shift = create_shift_with_details(shift) + return created_shift + + @staticmethod + def create_valid_volunteer(): + """ + Utility function to create a valid volunteer. + :return: Volunteer type object + """ + vol = [ + "Goku", "Son", "Goku", "Kame House", "East District", + "East District", "East District", "9999999999", "idonthave@gmail.com" + ] + return create_volunteer_with_details(vol) + + @staticmethod + def create_invalid_volunteer(): + """ + Utility function to create an invalid volunteer. + :return: Volunteer type object + """ + vol = [ + "Goku~", "Son", "Goku", "Kame House", "East District", + "East District", "East District", "9999999999", "idonthave@gmail.com" + ] + return create_volunteer_with_details(vol) + + @staticmethod + def create_volunteer_shift(shift, volunteer): + """ + Utility function to link a shift to a volunteer. + :return: VolunteerShift type object + """ + vol_shift = register_volunteer_for_shift_utility(shift, volunteer) + return vol_shift + + def test_valid_model_create(self): + """ + Database test for model creation with valid values. + """ + shift = self.create_shift() + volunteer = self.create_valid_volunteer() + + vol_shift = self.create_volunteer_shift(shift, volunteer) + + # Check db instance creation + self.assertEqual(len(VolunteerShift.objects.all()), 1) + + shift_in_db = Shift.objects.get(Q(job=self.job)) + vol_shift_in_db = VolunteerShift.objects.get(Q(shift=shift_in_db)) + # Verify correctness + self.assertEqual(str(vol_shift_in_db.shift.date), vol_shift.shift.date) + self.assertEqual(str(vol_shift_in_db.shift.start_time), vol_shift.shift.start_time) + self.assertEqual(str(vol_shift_in_db.shift.end_time), vol_shift.shift.end_time) + self.assertEqual(vol_shift_in_db.volunteer.first_name, vol_shift.volunteer.first_name) + self.assertEqual(vol_shift_in_db.volunteer.last_name, vol_shift.volunteer.last_name) + + def test_invalid_model_create(self): + """ + Database test for model creation with invalid values. + """ + shift = self.create_shift() + volunteer = self.create_invalid_volunteer() + + vol_shift = self.create_volunteer_shift(shift, volunteer) + + # Can't check error until clean method defined in model + # self.assertRaisesRegexp(ValidationError, BasePage.ENTER_VALID_VALUE, vol_shift.full_clean) + + def test_model_edit_with_valid_values(self): + """ + Database test for model edit with valid values. + """ + shift = self.create_shift() + volunteer = self.create_valid_volunteer() + + vol_shift = self.create_volunteer_shift(shift, volunteer) + + # Check db instance creation + self.assertEqual(len(VolunteerShift.objects.all()), 1) + + shift_in_db = Shift.objects.get(Q(job=self.job)) + volunteer_in_db = Volunteer.objects.get(Q(first_name='Son')) + vol_shift_in_db = VolunteerShift.objects.get(Q(shift=shift_in_db)) + # Verify correctness + self.assertEqual(str(vol_shift_in_db.shift.date), vol_shift.shift.date) + self.assertEqual(str(vol_shift_in_db.shift.start_time), vol_shift.shift.start_time) + self.assertEqual(str(vol_shift_in_db.shift.end_time), vol_shift.shift.end_time) + self.assertEqual(vol_shift_in_db.volunteer.first_name, vol_shift.volunteer.first_name) + self.assertEqual(vol_shift_in_db.volunteer.last_name, vol_shift.volunteer.last_name) + + volunteer_in_db.first_name = 'Prince' + volunteer_in_db.last_name = 'Vegeta' + volunteer_in_db.save() + vol_shift_in_db.volunteer = volunteer_in_db + vol_shift_in_db.save() + + # Check single instance + self.assertEqual(len(VolunteerShift.objects.all()), 1) + # Verify correctness + vol_shift_in_db = VolunteerShift.objects.get(Q(shift=shift_in_db)) + # Verify correctness + self.assertEqual(str(vol_shift_in_db.shift.date), vol_shift.shift.date) + self.assertEqual(str(vol_shift_in_db.shift.start_time), vol_shift.shift.start_time) + self.assertEqual(str(vol_shift_in_db.shift.end_time), vol_shift.shift.end_time) + self.assertEqual(vol_shift_in_db.volunteer.first_name, 'Prince') + self.assertEqual(vol_shift_in_db.volunteer.last_name, 'Vegeta') + + def test_model_edit_with_invalid_values(self): + """ + Database test for model edit with invalid values. + """ + shift = self.create_shift() + volunteer = self.create_valid_volunteer() + + vol_shift = self.create_volunteer_shift(shift, volunteer) + + # Check db instance creation + self.assertEqual(len(VolunteerShift.objects.all()), 1) + + shift_in_db = Shift.objects.get(Q(job=self.job)) + vol_shift_in_db = VolunteerShift.objects.get(Q(shift=shift_in_db)) + # Verify correctness + self.assertEqual(str(vol_shift_in_db.shift.date), vol_shift.shift.date) + self.assertEqual(str(vol_shift_in_db.shift.start_time), vol_shift.shift.start_time) + self.assertEqual(str(vol_shift_in_db.shift.end_time), vol_shift.shift.end_time) + self.assertEqual(vol_shift_in_db.volunteer.first_name, vol_shift.volunteer.first_name) + self.assertEqual(vol_shift_in_db.volunteer.last_name, vol_shift.volunteer.last_name) + + vol_shift_in_db.volunteer.first_name = 'Son~' + + # Can't check error until clean method defined in model + # self.assertRaisesRegexp(ValidationError, BasePage.ENTER_VALID_VALUE, vol_shift_in_db.full_clean) + + def test_model_delete(self): + """ + Database test for model deletion. + """ + shift = self.create_shift() + volunteer = self.create_valid_volunteer() + + vol_shift = self.create_volunteer_shift(shift, volunteer) + + # Check db instance creation + self.assertEqual(len(VolunteerShift.objects.all()), 1) + + shift_in_db = Shift.objects.get(Q(job=self.job)) + vol_shift_in_db = VolunteerShift.objects.get(Q(shift=shift_in_db)) + # Verify correctness + self.assertEqual(str(vol_shift_in_db.shift.date), vol_shift.shift.date) + self.assertEqual(str(vol_shift_in_db.shift.start_time), vol_shift.shift.start_time) + self.assertEqual(str(vol_shift_in_db.shift.end_time), vol_shift.shift.end_time) + self.assertEqual(str(vol_shift_in_db.shift.max_volunteers), vol_shift.shift.max_volunteers) + self.assertEqual(vol_shift_in_db.volunteer.first_name, vol_shift.volunteer.first_name) + self.assertEqual(vol_shift_in_db.volunteer.last_name, vol_shift.volunteer.last_name) + self.assertEqual(vol_shift_in_db.volunteer.email, vol_shift.volunteer.email) + self.assertEqual(vol_shift_in_db.volunteer.phone_number, vol_shift.volunteer.phone_number) + + vol_shift_in_db.delete() + # Check no instance in db + self.assertEqual(len(VolunteerShift.objects.all()), 0) + + def test_model_representation(self): + """ + Database test for model representation. + """ + shift = self.create_shift() + volunteer = self.create_valid_volunteer() + + vol_shift = self.create_volunteer_shift(shift, volunteer) + + # Check db instance creation + self.assertEqual(len(VolunteerShift.objects.all()), 1) + + shift_in_db = Shift.objects.get(Q(job=self.job)) + vol_shift_in_db = VolunteerShift.objects.get(Q(shift=shift_in_db)) -# Create your tests here. + # Check correctness + self.assertEqual(str(vol_shift_in_db), 'job-name - 2050-05-24 - Son') diff --git a/vms/shift/tests/test_viewVolunteerShift.py b/vms/shift/tests/test_viewVolunteerShift.py index f842fc5..66c39fa 100644 --- a/vms/shift/tests/test_viewVolunteerShift.py +++ b/vms/shift/tests/test_viewVolunteerShift.py @@ -4,6 +4,10 @@ # third party from selenium import webdriver from selenium.common.exceptions import NoSuchElementException +from selenium.webdriver.support.ui import WebDriverWait +from selenium.webdriver.support import expected_conditions as EC +from selenium.webdriver.common.by import By + # Django from django.contrib.staticfiles.testing import LiveServerTestCase @@ -12,106 +16,168 @@ from pom.pages.authenticationPage import AuthenticationPage from pom.pages.manageShiftPage import ManageShiftPage from pom.pages.upcomingShiftsPage import UpcomingShiftsPage -from shift.models import VolunteerShift - from shift.utils import (create_volunteer, create_event_with_details, create_job_with_details, create_shift_with_details, - register_volunteer_for_shift_utility) + register_volunteer_for_shift_utility, create_volunteer_with_details) -# Class contains failing test cases which have been documented -# Test class commented out to prevent travis build failure -""" class ViewVolunteerShift(LiveServerTestCase): - ''' - ''' + """ + Contains Tests for View Volunteer Shift Details Page + + Status of shift page is checked for following cases - + - Access another registered volunteer + - Access another unregistered volunteer + - Access no assigned shifts view + - Log hours and Shift not displayed in Upcoming Shifts + - View Assigned and Unlogged shifts + - Cancel shift registration + """ @classmethod def setUpClass(cls): + """Method to initiate class level objects. + + This method initiates Firefox WebDriver, WebDriverWait and + the corresponding POM objects for this Test Class + """ cls.driver = webdriver.Firefox() cls.driver.implicitly_wait(5) cls.driver.maximize_window() cls.manage_shift_page = ManageShiftPage(cls.driver) cls.upcoming_shift_page = UpcomingShiftsPage(cls.driver) cls.authentication_page = AuthenticationPage(cls.driver) + cls.wait = WebDriverWait(cls.driver, 10) super(ViewVolunteerShift, cls).setUpClass() def setUp(self): + """ + Method consists of statements to be executed before + start of each test. + """ self.v1 = create_volunteer() self.login_volunteer() def tearDown(self): - pass + """ + Method consists of statements to be executed at + end of each test. + """ + self.authentication_page.logout() @classmethod def tearDownClass(cls): + """ + Class method to quit the Firefox WebDriver session after + execution of all tests in class. + """ cls.driver.quit() super(ViewVolunteerShift, cls).tearDownClass() def login_volunteer(self): - credentials = {'username': 'volunteer', 'password': 'volunteer'} + """ + Utility function to login as volunteer. + """ + credentials = { + 'username': 'volunteer', + 'password': 'volunteer' + } self.authentication_page.server_url = self.live_server_url self.authentication_page.login(credentials) - def test_access_another_existing_volunteer_view(self): - ''' - details = ['test_volunteer', 'volunteer-first-nameq', 'volunteer-last-nameq', - 'volunteer-addressq', 'volunteer-city', 'volunteer-stateq', 'volunteer-countryq', - '9999999999', 'volunteer-email2@systers.orgq','volunteer-organizationq'] - - test_volunteer = create_volunteer_with_details(details) + def register_dataset(self): + """ + Utility function to register data for testing. + """ + created_event = create_event_with_details( + ['event-four', '2050-06-01', '2050-06-10']) + created_job = create_job_with_details([ + 'jobOneInEventFour', '2050-06-01', '2050-06-10', 'job description', + created_event + ]) + created_shift = create_shift_with_details( + ['2050-06-01', '09:00', '15:00', '10', created_job]) + registered_shift = register_volunteer_for_shift_utility(created_shift, self.v1) - self.login_volunteer() + def test_access_another_existing_volunteer_view(self): + """ + Test error raised while volunteer is trying to access profile page of + another existing volunteer. + """ upcoming_shift_page = self.upcoming_shift_page - upcoming_shift_page.get_page(self.live_server_url, upcoming_shift_page.view_shift_page + str(test_volunteer_id)) - ''' - pass + upcoming_shift_page.live_server_url = self.live_server_url + self.wait.until( + EC.presence_of_element_located( + (By.XPATH, + "//h1[contains(text(), 'Volunteer Management System')]" + ) + ) + ) + upcoming_shift_page.view_upcoming_shifts() + self.assertEqual(upcoming_shift_page.get_info_box(), + upcoming_shift_page.no_shift_message) + details = ['test_volunteer', 'volunteer-first-name', 'volunteer-last-name', + 'volunteer-address', 'volunteer-city', 'volunteer-state', 'volunteer-country', + '9999999999', 'volunteer-email2@systers.org', 'volunteer-organization'] + test_volunteer = create_volunteer_with_details(details) + upcoming_shift_page.get_page(upcoming_shift_page.live_server_url, + upcoming_shift_page.view_shift_page + str(test_volunteer.id)) + found = re.search('You don\'t have the required rights', + self.driver.page_source) + self.assertNotEqual(found, None) def test_access_another_nonexisting_volunteer_view(self): + """ + Test error raised while volunteer is trying to access profile page of + another non-existing volunteer. + """ upcoming_shift_page = self.upcoming_shift_page + upcoming_shift_page.live_server_url = self.live_server_url + self.wait.until( + EC.presence_of_element_located( + (By.XPATH, + "//h1[contains(text(), 'Volunteer Management System')]" + ) + ) + ) upcoming_shift_page.get_page( - self.live_server_url, - upcoming_shift_page.view_shift_page + '65459') + upcoming_shift_page.live_server_url, + upcoming_shift_page.view_shift_page + '65459' + ) found = re.search('You don\'t have the required rights', self.driver.page_source) self.assertNotEqual(found, None) def test_view_without_any_assigned_shift(self): + """ + Test display of shifts with no assigned shifts. + """ upcoming_shift_page = self.upcoming_shift_page upcoming_shift_page.view_upcoming_shifts() self.assertEqual(upcoming_shift_page.get_info_box(), upcoming_shift_page.no_shift_message) - def register_dataset(self): - - created_event = create_event_with_details( - ['event-four', '2017-06-01', '2017-06-10']) - created_job = create_job_with_details([ - 'jobOneInEventFour', '2017-06-01', '2017-06-10', 'job description', - created_event - ]) - created_shift = create_shift_with_details( - ['2017-06-01', '09:00', '15:00', '10', created_job]) - registered_shift = register_volunteer_for_shift_utility( - created_shift, self.v1) - def test_view_with_assigned_and_unlogged_shift(self): - + """ + Test display of assigned but unlogged shift. + """ self.register_dataset() upcoming_shift_page = self.upcoming_shift_page + upcoming_shift_page.live_server_url = self.live_server_url upcoming_shift_page.view_upcoming_shifts() - self.assertEqual(upcoming_shift_page.get_shift_job(), - 'jobOneInEventFour') - self.assertEqual(upcoming_shift_page.get_shift_date(), 'June 1, 2017') + self.assertEqual(upcoming_shift_page.get_shift_job(), 'jobOneInEventFour') + self.assertEqual(upcoming_shift_page.get_shift_date(), 'June 1, 2050') self.assertEqual(upcoming_shift_page.get_shift_start_time(), '9 a.m.') self.assertEqual(upcoming_shift_page.get_shift_end_time(), '3 p.m.') - def test_log_hours_and_logged_shift_does_not_appear_in_upcoming_shifts( - self): - + def test_log_hours_and_logged_shift_does_not_appear_in_upcoming_shifts(self): + """ + Test that already logged shift and hours do not appear in upcoming shifts. + """ self.register_dataset() upcoming_shift_page = self.upcoming_shift_page + upcoming_shift_page.live_server_url = self.live_server_url upcoming_shift_page.view_upcoming_shifts() self.assertEqual(upcoming_shift_page.get_log_hours(), 'Log Hours') @@ -119,28 +185,21 @@ def test_log_hours_and_logged_shift_does_not_appear_in_upcoming_shifts( upcoming_shift_page.click_to_log_hours() upcoming_shift_page.log_shift_timings('09:00', '12:00') - # check logged shift does not appear in Upcoming Shifts + # Check logged shift does not appear in Upcoming Shifts upcoming_shift_page.view_upcoming_shifts() self.assertEqual(upcoming_shift_page.get_info_box(), upcoming_shift_page.no_shift_message) - with self.assertRaises(NoSuchElementException): - upcoming_shift_page.get_result_container() - - # database check to ensure volunteer has logged the hours - self.assertEqual(len(VolunteerShift.objects.all()), 1) - self.assertNotEqual( - len( - VolunteerShift.objects.filter( - start_time__isnull=False, end_time__isnull=False)), 0) - self.assertNotEqual( - len( - VolunteerShift.objects.filter( - start_time='09:00', end_time='12:00')), 0) + self.assertRaisesRegexp(NoSuchElementException, + 'Unable to locate element: //table', + upcoming_shift_page.get_result_container) def test_cancel_shift_registration(self): - + """ + Test cancellation of registered shift. + """ self.register_dataset() upcoming_shift_page = self.upcoming_shift_page + upcoming_shift_page.live_server_url = self.live_server_url manage_shift_page = self.manage_shift_page upcoming_shift_page.view_upcoming_shifts() @@ -159,9 +218,6 @@ def test_cancel_shift_registration(self): upcoming_shift_page.view_upcoming_shifts() self.assertEqual(upcoming_shift_page.get_info_box(), upcoming_shift_page.no_shift_message) - with self.assertRaises(NoSuchElementException): - upcoming_shift_page.get_result_container() - - # database check to ensure shift registration is cancelled - self.assertEqual(len(VolunteerShift.objects.all()), 0) -""" + self.assertRaisesRegexp(NoSuchElementException, + 'Unable to locate element: //table', + upcoming_shift_page.get_result_container) diff --git a/vms/shift/utils.py b/vms/shift/utils.py index 70f6a5f..370c6b6 100644 --- a/vms/shift/utils.py +++ b/vms/shift/utils.py @@ -101,12 +101,23 @@ def create_shift_with_details(shift): """ Creates and returns shift with passed name and dates """ - s1 = Shift( - date=shift[0], - start_time=shift[1], - end_time=shift[2], - max_volunteers=shift[3], - job=shift[4]) + if len(shift) == 5: + s1 = Shift( + date=shift[0], + start_time=shift[1], + end_time=shift[2], + max_volunteers=shift[3], + job=shift[4]) + elif len(shift) == 7: + s1 = Shift( + date=shift[0], + start_time=shift[1], + end_time=shift[2], + max_volunteers=shift[3], + job=shift[4], + address=shift[5], + venue=shift[6] + ) s1.save() return s1 diff --git a/vms/shift/views.py b/vms/shift/views.py index 92558e1..90ddaad 100644 --- a/vms/shift/views.py +++ b/vms/shift/views.py @@ -1,728 +1,728 @@ -# standard library -from datetime import date - -# third party -from braces.views import LoginRequiredMixin - -# Django -from django.contrib import messages -from django.contrib.auth.decorators import login_required -from django.core.exceptions import ObjectDoesNotExist -from django.core.urlresolvers import reverse, reverse_lazy -from django.http import Http404, HttpResponse, HttpResponseRedirect -from django.shortcuts import render -from django.views.generic import TemplateView, DeleteView, ListView -from django.views.generic.edit import FormView, UpdateView -from django.utils.decorators import method_decorator - -# local Django -from job.models import Job -from job.services import get_job_by_id -from shift.forms import HoursForm, ShiftForm -from shift.models import Shift -from shift.services import get_shift_by_id, add_shift_hours, cancel_shift_registration, clear_shift_hours, edit_shift_hours, get_unlogged_shifts_by_volunteer_id, get_logged_volunteers_by_shift_id, get_shift_slots_remaining, get_volunteers_by_shift_id, get_volunteer_by_id, get_volunteer_shifts_with_hours, get_shifts_ordered_by_date, get_shifts_with_open_slots_for_volunteer, register, get_volunteer_shift_by_id, get_shifts_by_job_id, delete_shift -from volunteer.forms import SearchVolunteerForm -from volunteer.services import get_all_volunteers, search_volunteers -from volunteer.utils import vol_id_check -from vms.utils import check_correct_volunteer - - -class AdministratorLoginRequiredMixin(object): - @method_decorator(login_required) - def dispatch(self, request, *args, **kwargs): - user = request.user - admin = None - try: - admin = user.administrator - except ObjectDoesNotExist: - pass - if not admin: - return render(request, 'vms/no_admin_rights.html') - else: - return super(AdministratorLoginRequiredMixin, self).dispatch( - request, *args, **kwargs) - - -class AddHoursView(LoginRequiredMixin, FormView): - template_name = 'shift/add_hours.html' - form_class = HoursForm - - @method_decorator(check_correct_volunteer) - def dispatch(self, *args, **kwargs): - return super(AddHoursView, self).dispatch(*args, **kwargs) - - def get_context_data(self, **kwargs): - context = super(AddHoursView, self).get_context_data(**kwargs) - shift_id = self.kwargs['shift_id'] - volunteer_id = self.kwargs['volunteer_id'] - context['volunteer_id'] = volunteer_id - context['shift_id'] = shift_id - context['shift'] = get_shift_by_id(shift_id) - return context - - def form_valid(self, form): - shift_id = self.kwargs['shift_id'] - volunteer_id = self.kwargs['volunteer_id'] - shift = get_shift_by_id(shift_id) - start_time = form.cleaned_data['start_time'] - end_time = form.cleaned_data['end_time'] - shift_start_time = shift.start_time - shift_end_time = shift.end_time - try: - if (end_time > start_time): - if (start_time >= shift_start_time - and end_time <= shift_end_time): - add_shift_hours(volunteer_id, shift_id, start_time, - end_time) - return HttpResponseRedirect( - reverse('shift:view_hours', args=(volunteer_id, ))) - else: - messages.add_message( - self.request, messages.INFO, - 'Logged hours should be between shift hours') - return render( - self.request, 'shift/add_hours.html', { - 'form': form, - 'shift_id': shift_id, - 'volunteer_id': volunteer_id, - 'shift': shift, - }) - else: - messages.add_message( - self.request, messages.INFO, - 'End time should be greater than start time') - return render( - self.request, 'shift/add_hours.html', { - 'form': form, - 'shift_id': shift_id, - 'volunteer_id': volunteer_id, - 'shift': shift, - }) - except: - raise Http404 - - -class AddHoursManagerView(AdministratorLoginRequiredMixin, FormView): - template_name = 'shift/add_hours_manager.html' - form_class = HoursForm - - def get_context_data(self, **kwargs): - context = super(AddHoursManagerView, self).get_context_data(**kwargs) - shift_id = self.kwargs['shift_id'] - volunteer_id = self.kwargs['volunteer_id'] - context['volunteer_id'] = volunteer_id - context['shift_id'] = shift_id - context['shift'] = get_shift_by_id(shift_id) - return context - - def form_valid(self, form): - shift_id = self.kwargs['shift_id'] - volunteer_id = self.kwargs['volunteer_id'] - shift = get_shift_by_id(shift_id) - start_time = form.cleaned_data['start_time'] - end_time = form.cleaned_data['end_time'] - shift_start_time = shift.start_time - shift_end_time = shift.end_time - try: - if (end_time > start_time): - if (start_time >= shift_start_time - and end_time <= shift_end_time): - add_shift_hours(volunteer_id, shift_id, start_time, - end_time) - return HttpResponseRedirect( - reverse( - 'shift:manage_volunteer_shifts', - args=(volunteer_id, ))) - else: - messages.add_message( - self.request, messages.INFO, - 'Logged hours should be between shift hours') - return render( - self.request, 'shift/add_hours_manager.html', { - 'form': form, - 'shift_id': shift_id, - 'volunteer_id': volunteer_id, - 'shift': shift, - }) - - else: - messages.add_message( - self.request, messages.INFO, - 'End time should be greater than start time') - return render( - self.request, 'shift/add_hours_manager.html', { - 'form': form, - 'shift_id': shift_id, - 'volunteer_id': volunteer_id, - 'shift': shift, - }) - except: - raise Http404 - - -@login_required -def cancel(request, shift_id, volunteer_id): - - if shift_id and volunteer_id: - - user = request.user - admin = None - volunteer = None - - try: - admin = user.administrator - except ObjectDoesNotExist: - pass - try: - volunteer = user.volunteer - except ObjectDoesNotExist: - pass - - # check that either an admin or volunteer is logged in - if not admin and not volunteer: - return render(request, 'vms/no_volunteer_rights.html', status=403) - - # if a volunteer is logged in, verify that they are canceling their own shift - if volunteer: - if (int(volunteer.id) != int(volunteer_id)): - return render( - request, 'vms/no_volunteer_rights.html', status=403) - - if request.method == 'POST': - try: - cancel_shift_registration(volunteer_id, shift_id) - if admin: - return HttpResponseRedirect( - reverse( - 'shift:manage_volunteer_shifts', - args=(volunteer_id, ))) - elif volunteer: - return HttpResponseRedirect( - reverse( - 'shift:view_volunteer_shifts', - args=(volunteer_id, ))) - else: - raise Http404 - except: - raise Http404 - else: - return render(request, 'shift/cancel_shift.html', { - 'shift_id': shift_id, - 'volunteer_id': volunteer_id - }) - else: - raise Http404 - - -class ClearHoursView(LoginRequiredMixin, TemplateView): - template_name = 'shift/clear_hours.html' - success_url = reverse_lazy('shift:view_hours') - - def get_context_data(self, **kwargs): - context = super(ClearHoursView, self).get_context_data(**kwargs) - shift_id = self.kwargs['shift_id'] - volunteer_id = self.kwargs['volunteer_id'] - context['volunteer_id'] = volunteer_id - context['shift_id'] = shift_id - context['result'] = clear_shift_hours(volunteer_id, shift_id) - return context - - def post(self, request, *args, **kwargs): - volunteer_id = self.kwargs['volunteer_id'] - shift_id = self.kwargs['shift_id'] - result = clear_shift_hours(volunteer_id, shift_id) - if result: - return HttpResponseRedirect( - reverse('shift:view_hours', args=(volunteer_id, ))) - else: - raise Http404 - - -class ClearHoursManager(AdministratorLoginRequiredMixin, TemplateView): - template_name = 'shift/clear_hours.html' - - def get_context_data(self, **kwargs): - context = super(ClearHoursManager, self).get_context_data(**kwargs) - shift_id = self.kwargs['shift_id'] - volunteer_id = self.kwargs['volunteer_id'] - context['volunteer_id'] = volunteer_id - context['shift_id'] = shift_id - context['result'] = clear_shift_hours(volunteer_id, shift_id) - return context - - def post(self, request, *args, **kwargs): - volunteer_id = self.kwargs['volunteer_id'] - shift_id = self.kwargs['shift_id'] - result = clear_shift_hours(volunteer_id, shift_id) - if result: - return HttpResponseRedirect( - reverse( - 'shift:manage_volunteer_shifts', args=(volunteer_id, ))) - else: - raise Http404 - - -class ShiftCreateView(AdministratorLoginRequiredMixin, FormView): - template_name = 'shift/create.html' - form_class = ShiftForm - success_url = 'shift:list_shifts' - - def get_context_data(self, **kwargs): - context = super(ShiftCreateView, self).get_context_data(**kwargs) - job_id = self.kwargs['job_id'] - context['job_id'] = job_id - job = get_job_by_id(job_id) - event = job.event - context['job'] = job - context['event'] = job.event - context['country'] = event.country - context['state'] = event.state - context['city'] = event.city - context['address'] = event.address - context['venue'] = event.venue - return context - - def form_valid(self, form): - job_id = self.kwargs['job_id'] - job = get_job_by_id(job_id) - start_date_job = job.start_date - end_date_job = job.end_date - shift_date = form.cleaned_data['date'] - shift_start_time = form.cleaned_data['start_time'] - shift_end_time = form.cleaned_data['end_time'] - if (shift_date >= start_date_job and shift_date <= end_date_job - and shift_end_time > shift_start_time): - shift = form.save(commit=False) - shift.job = job - shift.save() - return HttpResponseRedirect( - reverse('shift:list_shifts', args=(job_id, ))) - else: - if (shift_date < start_date_job or shift_date > end_date_job): - messages.add_message(self.request, messages.INFO, - 'Shift date should lie within Job dates') - if shift_end_time <= shift_start_time: - messages.add_message( - self.request, messages.INFO, - 'Shift end time should be greater than start time') - return render(self.request, 'shift/create.html', { - 'form': form, - 'job_id': job_id, - 'job': job - }) - - -class ShiftDeleteView(AdministratorLoginRequiredMixin, DeleteView): - model_form = Shift - template_name = 'shift/delete.html' - success_url = reverse_lazy('shift:list_jobs') - - def get_object(self, queryset=None): - shift_id = self.kwargs['shift_id'] - shift = Shift.objects.get(pk=shift_id) - if shift: - return shift - - def delete(self, request, *args, **kwargs): - shift_id = self.kwargs['shift_id'] - shift = self.get_object() - job_id = shift.job.id - result = delete_shift(shift_id) - if result: - shift_list = get_shifts_by_job_id(job_id) - if shift_list: - return HttpResponseRedirect( - reverse('shift:list_shifts', args=(job_id, ))) - else: - return HttpResponseRedirect(reverse('shift:list_jobs')) - else: - return render(request, 'shift/delete_error.html') - - -class ShiftUpdateView(AdministratorLoginRequiredMixin, UpdateView): - form_class = ShiftForm - template_name = 'shift/edit.html' - success_url = reverse_lazy('shift:list_shifts') - - def get_context_data(self, **kwargs): - context = super(ShiftUpdateView, self).get_context_data(**kwargs) - shift = get_shift_by_id(self.kwargs['shift_id']) - context['shift'] = shift - context['job'] = shift.job - return context - - def get_object(self, queryset=None): - shift_id = self.kwargs['shift_id'] - obj = Shift.objects.get(pk=shift_id) - return obj - - def form_valid(self, form): - shift_id = self.kwargs['shift_id'] - shift = get_shift_by_id(shift_id) - job = shift.job - start_date_job = job.start_date - end_date_job = job.end_date - shift_date = form.cleaned_data['date'] - shift_start_time = form.cleaned_data['start_time'] - shift_end_time = form.cleaned_data['end_time'] - max_vols = form.cleaned_data['max_volunteers'] - - # save when all conditions satisfied - if (shift_date >= start_date_job and shift_date <= end_date_job and shift_end_time > shift_start_time \ - and max_vols >= len(shift.volunteers.all())): - shift_to_edit = form.save(commit=False) - shift_to_edit.job = job - shift_to_edit.save() - return HttpResponseRedirect( - reverse('shift:list_shifts', args=(shift.job.id, ))) - else: - if (shift_date < start_date_job or shift_date > end_date_job): - messages.add_message(self.request, messages.INFO, - 'Shift date should lie within Job dates') - if shift_end_time <= shift_start_time: - messages.add_message( - self.request, messages.INFO, - 'Shift end time should be greater than start time') - if max_vols < len(shift.volunteers.all()): - messages.add_message( - self.request, messages.INFO, - 'Max volunteers should be greater than or equal to' - ' the already assigned volunteers.') - return render(self.request, 'shift/edit.html', { - 'form': form, - 'shift': shift, - 'job': shift.job - }) - - -class EditHoursView(LoginRequiredMixin, FormView): - template_name = 'shift/edit_hours.html' - form_class = HoursForm - - @method_decorator(check_correct_volunteer) - def dispatch(self, *args, **kwargs): - return super(EditHoursView, self).dispatch(*args, **kwargs) - - def get_context_data(self, **kwargs): - context = super(EditHoursView, self).get_context_data(**kwargs) - volunteer_id = self.kwargs['volunteer_id'] - shift_id = self.kwargs['shift_id'] - context['volunteer_shift'] = get_volunteer_shift_by_id( - volunteer_id, shift_id) - context['shift'] = get_shift_by_id(shift_id) - return context - - def form_valid(self, form): - volunteer_id = self.kwargs['volunteer_id'] - shift_id = self.kwargs['shift_id'] - shift = get_shift_by_id(shift_id) - volunteer_shift = get_volunteer_shift_by_id(volunteer_id, shift_id) - start_time = form.cleaned_data['start_time'] - end_time = form.cleaned_data['end_time'] - shift_start_time = shift.start_time - shift_end_time = shift.end_time - try: - if (end_time > start_time): - if (start_time >= shift_start_time - and end_time <= shift_end_time): - edit_shift_hours(volunteer_id, shift_id, start_time, - end_time) - return HttpResponseRedirect( - reverse('shift:view_hours', args=(volunteer_id, ))) - else: - messages.add_message( - self.request, messages.INFO, - 'Logged hours should be between shift hours') - return render( - self.request, 'shift/edit_hours.html', { - 'form': form, - 'shift_id': shift_id, - 'volunteer_id': volunteer_id, - 'shift': shift, - 'volunteer_shift': volunteer_shift, - }) - - else: - messages.add_message( - self.request, messages.INFO, - 'End time should be greater than start time') - return render( - self.request, 'shift/edit_hours.html', { - 'form': form, - 'shift_id': shift_id, - 'volunteer_id': volunteer_id, - 'shift': shift, - 'volunteer_shift': volunteer_shift, - }) - except: - raise Http404 - - -class EditHoursManagerView(AdministratorLoginRequiredMixin, FormView): - template_name = 'shift/edit_hours_manager.html' - form_class = HoursForm - - def get_context_data(self, **kwargs): - context = super(EditHoursManagerView, self).get_context_data(**kwargs) - volunteer_id = self.kwargs['volunteer_id'] - shift_id = self.kwargs['shift_id'] - context['volunteer_shift'] = get_volunteer_shift_by_id( - volunteer_id, shift_id) - context['shift'] = get_shift_by_id(shift_id) - return context - - def form_valid(self, form): - volunteer_id = self.kwargs['volunteer_id'] - shift_id = self.kwargs['shift_id'] - shift = get_shift_by_id(shift_id) - volunteer_shift = get_volunteer_shift_by_id(volunteer_id, shift_id) - start_time = form.cleaned_data['start_time'] - end_time = form.cleaned_data['end_time'] - shift_start_time = shift.start_time - shift_end_time = shift.end_time - try: - if (end_time > start_time): - if (start_time >= shift_start_time - and end_time <= shift_end_time): - edit_shift_hours(volunteer_id, shift_id, start_time, - end_time) - return HttpResponseRedirect( - reverse( - 'shift:manage_volunteer_shifts', - args=(volunteer_id, ))) - else: - messages.add_message( - self.request, messages.INFO, - 'Logged hours should be between shift hours') - return render( - self.request, 'shift/edit_hours_manager.html', { - 'form': form, - 'shift_id': shift_id, - 'volunteer_id': volunteer_id, - 'shift': shift, - 'volunteer_shift': volunteer_shift, - }) - - else: - messages.add_message( - self.request, messages.INFO, - 'End time should be greater than start time') - return render( - self.request, 'shift/edit_hours_manager.html', { - 'form': form, - 'shift_id': shift_id, - 'volunteer_id': volunteer_id, - 'shift': shift, - 'volunteer_shift': volunteer_shift, - }) - - except: - raise Http404 - - -class JobListView(AdministratorLoginRequiredMixin, - ListView): # Replaced by list_jobs - template_name = 'shift/list_jobs.html' - model_form = Job - - def get_queryset(self): - job = Job.objects.all().order_by('name') - return job - - -class ShiftListView(AdministratorLoginRequiredMixin, - TemplateView): # Replaced by list_shifts - template_name = 'shift/list_shifts.html' - - def get_context_data(self, **kwargs): - context = super(ShiftListView, self).get_context_data(**kwargs) - job_id = self.kwargs['job_id'] - context['shift_list'] = get_shifts_ordered_by_date(job_id) - return context - - -@login_required -def list_shifts_sign_up(request, job_id, volunteer_id): - if job_id: - job = get_job_by_id(job_id) - if job: - shift_list = [] - shift_list_all = get_shifts_with_open_slots_for_volunteer( - job_id, volunteer_id) - for shift in shift_list_all: - sdate = shift["date"] - today = date.today() - if sdate >= today: - shift_list.append(shift) - return render(request, 'shift/list_shifts_sign_up.html', { - 'shift_list': shift_list, - 'job': job, - 'volunteer_id': volunteer_id - }) - else: - raise Http404 - else: - raise Http404 - - -class ManageVolunteerShiftView(AdministratorLoginRequiredMixin, TemplateView): - template_name = 'shift/manage_volunteer_shifts.html' - - def get_context_data(self, **kwargs): - context = super(ManageVolunteerShiftView, self).get_context_data( - **kwargs) - volunteer_id = self.kwargs['volunteer_id'] - context['volunteer'] = get_volunteer_by_id(volunteer_id) - context['shift_list'] = get_unlogged_shifts_by_volunteer_id( - volunteer_id) - context['shift_list_with_hours'] = get_volunteer_shifts_with_hours( - volunteer_id) - return context - - -@login_required -def sign_up(request, shift_id, volunteer_id): - if shift_id: - shift = get_shift_by_id(shift_id) - if shift: - - user = request.user - admin = None - volunteer = None - - try: - admin = user.administrator - except ObjectDoesNotExist: - pass - try: - volunteer = user.volunteer - except ObjectDoesNotExist: - pass - - if not admin and not volunteer: - return HttpResponse(status=403) - - if volunteer: - if (int(volunteer.id) != int(volunteer_id)): - return HttpResponse(status=403) - - if request.method == 'POST': - try: - result = register(volunteer_id, shift_id) - if result == "IS_VALID": - if admin: - return HttpResponseRedirect( - reverse( - 'shift:manage_volunteer_shifts', - args=(volunteer_id, ))) - if volunteer: - return HttpResponseRedirect( - reverse( - 'shift:view_volunteer_shifts', - args=(volunteer_id, ))) - else: - return render(request, 'shift/sign_up_error.html', { - 'error_code': result - }) - except ObjectDoesNotExist: - raise Http404 - else: - return render(request, 'shift/sign_up.html', { - 'shift': shift, - 'volunteer_id': volunteer_id - }) - else: - raise Http404 - else: - raise Http404 - - -class ViewHoursView(LoginRequiredMixin, FormView, TemplateView): - template_name = 'shift/hours_list.html' - form_class = HoursForm - - @method_decorator(check_correct_volunteer) - @method_decorator(vol_id_check) - def dispatch(self, *args, **kwargs): - return super(ViewHoursView, self).dispatch(*args, **kwargs) - - def get_context_data(self, **kwargs): - context = super(ViewHoursView, self).get_context_data(**kwargs) - volunteer_id = self.kwargs['volunteer_id'] - context['volunteer'] = get_volunteer_by_id(volunteer_id) - context['volunteer_shift_list'] = get_volunteer_shifts_with_hours( - volunteer_id) - return context - - -@login_required -@check_correct_volunteer -@vol_id_check -def view_volunteer_shifts(request, volunteer_id): - shift_list = get_unlogged_shifts_by_volunteer_id(volunteer_id) - return render(request, 'shift/volunteer_shifts.html', { - 'shift_list': shift_list, - 'volunteer_id': volunteer_id, - }) - - -class VolunteerSearchView(AdministratorLoginRequiredMixin, FormView): - template_name = 'shift/volunteer_search.html' - form_class = SearchVolunteerForm - success_url = 'volunteer_list' - - def get_context_data(self, **kwargs): - context = super(VolunteerSearchView, self).get_context_data(**kwargs) - context['volunteer_list'] = get_all_volunteers() - context['has_searched'] = False - return context - - def form_valid(self, form): - first_name = form.cleaned_data['first_name'] - last_name = form.cleaned_data['last_name'] - city = form.cleaned_data['city'] - state = form.cleaned_data['state'] - country = form.cleaned_data['country'] - organization = form.cleaned_data['organization'] - - volunteer_list = search_volunteers(first_name, last_name, city, state, - country, organization) - return render(self.request, 'shift/volunteer_search.html', { - 'form': form, - 'has_searched': True, - 'volunteer_list': volunteer_list - }) - - -@login_required -def view_volunteers(request, shift_id): - user = request.user - admin = None - - try: - admin = user.administrator - except ObjectDoesNotExist: - pass - - # check that an admin is logged in - if not admin: - return render(request, 'vms/no_admin_rights.html') - else: - if shift_id: - shift = get_shift_by_id(shift_id) - if shift: - volunteer_list = get_volunteers_by_shift_id(shift_id) - logged_volunteer_list = get_logged_volunteers_by_shift_id( - shift_id) - slots_remaining = get_shift_slots_remaining(shift_id) - return render( - request, 'shift/list_volunteers.html', { - 'volunteer_list': volunteer_list, - 'shift': shift, - 'slots_remaining': slots_remaining, - 'logged_volunteer_list': logged_volunteer_list - }) - else: - raise Http404 - else: - raise Http404 +# standard library +from datetime import date + +# third party +from braces.views import LoginRequiredMixin + +# Django +from django.contrib import messages +from django.contrib.auth.decorators import login_required +from django.core.exceptions import ObjectDoesNotExist +from django.core.urlresolvers import reverse, reverse_lazy +from django.http import Http404, HttpResponse, HttpResponseRedirect +from django.shortcuts import render +from django.views.generic import TemplateView, DeleteView, ListView +from django.views.generic.edit import FormView, UpdateView +from django.utils.decorators import method_decorator + +# local Django +from job.models import Job +from job.services import get_job_by_id +from shift.forms import HoursForm, ShiftForm +from shift.models import Shift +from shift.services import get_shift_by_id, add_shift_hours, cancel_shift_registration, clear_shift_hours, edit_shift_hours, get_unlogged_shifts_by_volunteer_id, get_logged_volunteers_by_shift_id, get_shift_slots_remaining, get_volunteers_by_shift_id, get_volunteer_by_id, get_volunteer_shifts_with_hours, get_shifts_ordered_by_date, get_shifts_with_open_slots_for_volunteer, register, get_volunteer_shift_by_id, get_shifts_by_job_id, delete_shift +from volunteer.forms import SearchVolunteerForm +from volunteer.services import get_all_volunteers, search_volunteers +from volunteer.utils import vol_id_check +from vms.utils import check_correct_volunteer + + +class AdministratorLoginRequiredMixin(object): + @method_decorator(login_required) + def dispatch(self, request, *args, **kwargs): + user = request.user + admin = None + try: + admin = user.administrator + except ObjectDoesNotExist: + pass + if not admin: + return render(request, 'vms/no_admin_rights.html') + else: + return super(AdministratorLoginRequiredMixin, self).dispatch( + request, *args, **kwargs) + + +class AddHoursView(LoginRequiredMixin, FormView): + template_name = 'shift/add_hours.html' + form_class = HoursForm + + @method_decorator(check_correct_volunteer) + def dispatch(self, *args, **kwargs): + return super(AddHoursView, self).dispatch(*args, **kwargs) + + def get_context_data(self, **kwargs): + context = super(AddHoursView, self).get_context_data(**kwargs) + shift_id = self.kwargs['shift_id'] + volunteer_id = self.kwargs['volunteer_id'] + context['volunteer_id'] = volunteer_id + context['shift_id'] = shift_id + context['shift'] = get_shift_by_id(shift_id) + return context + + def form_valid(self, form): + shift_id = self.kwargs['shift_id'] + volunteer_id = self.kwargs['volunteer_id'] + shift = get_shift_by_id(shift_id) + start_time = form.cleaned_data['start_time'] + end_time = form.cleaned_data['end_time'] + shift_start_time = shift.start_time + shift_end_time = shift.end_time + try: + if (end_time > start_time): + if (start_time >= shift_start_time + and end_time <= shift_end_time): + add_shift_hours(volunteer_id, shift_id, start_time, + end_time) + return HttpResponseRedirect( + reverse('shift:view_hours', args=(volunteer_id, ))) + else: + messages.add_message( + self.request, messages.INFO, + 'Logged hours should be between shift hours') + return render( + self.request, 'shift/add_hours.html', { + 'form': form, + 'shift_id': shift_id, + 'volunteer_id': volunteer_id, + 'shift': shift, + }) + else: + messages.add_message( + self.request, messages.INFO, + 'End time should be greater than start time') + return render( + self.request, 'shift/add_hours.html', { + 'form': form, + 'shift_id': shift_id, + 'volunteer_id': volunteer_id, + 'shift': shift, + }) + except: + raise Http404 + + +class AddHoursManagerView(AdministratorLoginRequiredMixin, FormView): + template_name = 'shift/add_hours_manager.html' + form_class = HoursForm + + def get_context_data(self, **kwargs): + context = super(AddHoursManagerView, self).get_context_data(**kwargs) + shift_id = self.kwargs['shift_id'] + volunteer_id = self.kwargs['volunteer_id'] + context['volunteer_id'] = volunteer_id + context['shift_id'] = shift_id + context['shift'] = get_shift_by_id(shift_id) + return context + + def form_valid(self, form): + shift_id = self.kwargs['shift_id'] + volunteer_id = self.kwargs['volunteer_id'] + shift = get_shift_by_id(shift_id) + start_time = form.cleaned_data['start_time'] + end_time = form.cleaned_data['end_time'] + shift_start_time = shift.start_time + shift_end_time = shift.end_time + try: + if (end_time > start_time): + if (start_time >= shift_start_time + and end_time <= shift_end_time): + add_shift_hours(volunteer_id, shift_id, start_time, + end_time) + return HttpResponseRedirect( + reverse( + 'shift:manage_volunteer_shifts', + args=(volunteer_id, ))) + else: + messages.add_message( + self.request, messages.INFO, + 'Logged hours should be between shift hours') + return render( + self.request, 'shift/add_hours_manager.html', { + 'form': form, + 'shift_id': shift_id, + 'volunteer_id': volunteer_id, + 'shift': shift, + }) + + else: + messages.add_message( + self.request, messages.INFO, + 'End time should be greater than start time') + return render( + self.request, 'shift/add_hours_manager.html', { + 'form': form, + 'shift_id': shift_id, + 'volunteer_id': volunteer_id, + 'shift': shift, + }) + except: + raise Http404 + + +@login_required +def cancel(request, shift_id, volunteer_id): + + if shift_id and volunteer_id: + + user = request.user + admin = None + volunteer = None + + try: + admin = user.administrator + except ObjectDoesNotExist: + pass + try: + volunteer = user.volunteer + except ObjectDoesNotExist: + pass + + # check that either an admin or volunteer is logged in + if not admin and not volunteer: + return render(request, 'vms/no_volunteer_rights.html', status=403) + + # if a volunteer is logged in, verify that they are canceling their own shift + if volunteer: + if (int(volunteer.id) != int(volunteer_id)): + return render( + request, 'vms/no_volunteer_rights.html', status=403) + + if request.method == 'POST': + try: + cancel_shift_registration(volunteer_id, shift_id) + if admin: + return HttpResponseRedirect( + reverse( + 'shift:manage_volunteer_shifts', + args=(volunteer_id, ))) + elif volunteer: + return HttpResponseRedirect( + reverse( + 'shift:view_volunteer_shifts', + args=(volunteer_id, ))) + else: + raise Http404 + except: + raise Http404 + else: + return render(request, 'shift/cancel_shift.html', { + 'shift_id': shift_id, + 'volunteer_id': volunteer_id + }) + else: + raise Http404 + + +class ClearHoursView(LoginRequiredMixin, TemplateView): + template_name = 'shift/clear_hours.html' + success_url = reverse_lazy('shift:view_hours') + + def get_context_data(self, **kwargs): + context = super(ClearHoursView, self).get_context_data(**kwargs) + shift_id = self.kwargs['shift_id'] + volunteer_id = self.kwargs['volunteer_id'] + context['volunteer_id'] = volunteer_id + context['shift_id'] = shift_id + context['result'] = clear_shift_hours(volunteer_id, shift_id) + return context + + def post(self, request, *args, **kwargs): + volunteer_id = self.kwargs['volunteer_id'] + shift_id = self.kwargs['shift_id'] + result = clear_shift_hours(volunteer_id, shift_id) + if result: + return HttpResponseRedirect( + reverse('shift:view_hours', args=(volunteer_id, ))) + else: + raise Http404 + + +class ClearHoursManager(AdministratorLoginRequiredMixin, TemplateView): + template_name = 'shift/clear_hours.html' + + def get_context_data(self, **kwargs): + context = super(ClearHoursManager, self).get_context_data(**kwargs) + shift_id = self.kwargs['shift_id'] + volunteer_id = self.kwargs['volunteer_id'] + context['volunteer_id'] = volunteer_id + context['shift_id'] = shift_id + context['result'] = clear_shift_hours(volunteer_id, shift_id) + return context + + def post(self, request, *args, **kwargs): + volunteer_id = self.kwargs['volunteer_id'] + shift_id = self.kwargs['shift_id'] + result = clear_shift_hours(volunteer_id, shift_id) + if result: + return HttpResponseRedirect( + reverse( + 'shift:manage_volunteer_shifts', args=(volunteer_id, ))) + else: + raise Http404 + + +class ShiftCreateView(AdministratorLoginRequiredMixin, FormView): + template_name = 'shift/create.html' + form_class = ShiftForm + success_url = 'shift:list_shifts' + + def get_context_data(self, **kwargs): + context = super(ShiftCreateView, self).get_context_data(**kwargs) + job_id = self.kwargs['job_id'] + context['job_id'] = job_id + job = get_job_by_id(job_id) + event = job.event + context['job'] = job + context['event'] = job.event + context['country'] = event.country + context['state'] = event.state + context['city'] = event.city + context['address'] = event.address + context['venue'] = event.venue + return context + + def form_valid(self, form): + job_id = self.kwargs['job_id'] + job = get_job_by_id(job_id) + start_date_job = job.start_date + end_date_job = job.end_date + shift_date = form.cleaned_data['date'] + shift_start_time = form.cleaned_data['start_time'] + shift_end_time = form.cleaned_data['end_time'] + if (shift_date >= start_date_job and shift_date <= end_date_job + and shift_end_time > shift_start_time): + shift = form.save(commit=False) + shift.job = job + shift.save() + return HttpResponseRedirect( + reverse('shift:list_shifts', args=(job_id, ))) + else: + if (shift_date < start_date_job or shift_date > end_date_job): + messages.add_message(self.request, messages.INFO, + 'Shift date should lie within Job dates') + if shift_end_time <= shift_start_time: + messages.add_message( + self.request, messages.INFO, + 'Shift end time should be greater than start time') + return render(self.request, 'shift/create.html', { + 'form': form, + 'job_id': job_id, + 'job': job + }) + + +class ShiftDeleteView(AdministratorLoginRequiredMixin, DeleteView): + model_form = Shift + template_name = 'shift/delete.html' + success_url = reverse_lazy('shift:list_jobs') + + def get_object(self, queryset=None): + shift_id = self.kwargs['shift_id'] + shift = Shift.objects.get(pk=shift_id) + if shift: + return shift + + def delete(self, request, *args, **kwargs): + shift_id = self.kwargs['shift_id'] + shift = self.get_object() + job_id = shift.job.id + result = delete_shift(shift_id) + if result: + shift_list = get_shifts_by_job_id(job_id) + if shift_list: + return HttpResponseRedirect( + reverse('shift:list_shifts', args=(job_id, ))) + else: + return HttpResponseRedirect(reverse('shift:list_jobs')) + else: + return render(request, 'shift/delete_error.html') + + +class ShiftUpdateView(AdministratorLoginRequiredMixin, UpdateView): + form_class = ShiftForm + template_name = 'shift/edit.html' + success_url = reverse_lazy('shift:list_shifts') + + def get_context_data(self, **kwargs): + context = super(ShiftUpdateView, self).get_context_data(**kwargs) + shift = get_shift_by_id(self.kwargs['shift_id']) + context['shift'] = shift + context['job'] = shift.job + return context + + def get_object(self, queryset=None): + shift_id = self.kwargs['shift_id'] + obj = Shift.objects.get(pk=shift_id) + return obj + + def form_valid(self, form): + shift_id = self.kwargs['shift_id'] + shift = get_shift_by_id(shift_id) + job = shift.job + start_date_job = job.start_date + end_date_job = job.end_date + shift_date = form.cleaned_data['date'] + shift_start_time = form.cleaned_data['start_time'] + shift_end_time = form.cleaned_data['end_time'] + max_vols = form.cleaned_data['max_volunteers'] + + # save when all conditions satisfied + if (shift_date >= start_date_job and shift_date <= end_date_job and shift_end_time > shift_start_time \ + and max_vols >= len(shift.volunteers.all())): + shift_to_edit = form.save(commit=False) + shift_to_edit.job = job + shift_to_edit.save() + return HttpResponseRedirect( + reverse('shift:list_shifts', args=(shift.job.id, ))) + else: + if (shift_date < start_date_job or shift_date > end_date_job): + messages.add_message(self.request, messages.INFO, + 'Shift date should lie within Job dates') + if shift_end_time <= shift_start_time: + messages.add_message( + self.request, messages.INFO, + 'Shift end time should be greater than start time') + if max_vols < len(shift.volunteers.all()): + messages.add_message( + self.request, messages.INFO, + 'Max volunteers should be greater than or equal to' + ' the already assigned volunteers.') + return render(self.request, 'shift/edit.html', { + 'form': form, + 'shift': shift, + 'job': shift.job + }) + + +class EditHoursView(LoginRequiredMixin, FormView): + template_name = 'shift/edit_hours.html' + form_class = HoursForm + + @method_decorator(check_correct_volunteer) + def dispatch(self, *args, **kwargs): + return super(EditHoursView, self).dispatch(*args, **kwargs) + + def get_context_data(self, **kwargs): + context = super(EditHoursView, self).get_context_data(**kwargs) + volunteer_id = self.kwargs['volunteer_id'] + shift_id = self.kwargs['shift_id'] + context['volunteer_shift'] = get_volunteer_shift_by_id( + volunteer_id, shift_id) + context['shift'] = get_shift_by_id(shift_id) + return context + + def form_valid(self, form): + volunteer_id = self.kwargs['volunteer_id'] + shift_id = self.kwargs['shift_id'] + shift = get_shift_by_id(shift_id) + volunteer_shift = get_volunteer_shift_by_id(volunteer_id, shift_id) + start_time = form.cleaned_data['start_time'] + end_time = form.cleaned_data['end_time'] + shift_start_time = shift.start_time + shift_end_time = shift.end_time + try: + if (end_time > start_time): + if (start_time >= shift_start_time + and end_time <= shift_end_time): + edit_shift_hours(volunteer_id, shift_id, start_time, + end_time) + return HttpResponseRedirect( + reverse('shift:view_hours', args=(volunteer_id, ))) + else: + messages.add_message( + self.request, messages.INFO, + 'Logged hours should be between shift hours') + return render( + self.request, 'shift/edit_hours.html', { + 'form': form, + 'shift_id': shift_id, + 'volunteer_id': volunteer_id, + 'shift': shift, + 'volunteer_shift': volunteer_shift, + }) + + else: + messages.add_message( + self.request, messages.INFO, + 'End time should be greater than start time') + return render( + self.request, 'shift/edit_hours.html', { + 'form': form, + 'shift_id': shift_id, + 'volunteer_id': volunteer_id, + 'shift': shift, + 'volunteer_shift': volunteer_shift, + }) + except: + raise Http404 + + +class EditHoursManagerView(AdministratorLoginRequiredMixin, FormView): + template_name = 'shift/edit_hours_manager.html' + form_class = HoursForm + + def get_context_data(self, **kwargs): + context = super(EditHoursManagerView, self).get_context_data(**kwargs) + volunteer_id = self.kwargs['volunteer_id'] + shift_id = self.kwargs['shift_id'] + context['volunteer_shift'] = get_volunteer_shift_by_id( + volunteer_id, shift_id) + context['shift'] = get_shift_by_id(shift_id) + return context + + def form_valid(self, form): + volunteer_id = self.kwargs['volunteer_id'] + shift_id = self.kwargs['shift_id'] + shift = get_shift_by_id(shift_id) + volunteer_shift = get_volunteer_shift_by_id(volunteer_id, shift_id) + start_time = form.cleaned_data['start_time'] + end_time = form.cleaned_data['end_time'] + shift_start_time = shift.start_time + shift_end_time = shift.end_time + try: + if (end_time > start_time): + if (start_time >= shift_start_time + and end_time <= shift_end_time): + edit_shift_hours(volunteer_id, shift_id, start_time, + end_time) + return HttpResponseRedirect( + reverse( + 'shift:manage_volunteer_shifts', + args=(volunteer_id, ))) + else: + messages.add_message( + self.request, messages.INFO, + 'Logged hours should be between shift hours') + return render( + self.request, 'shift/edit_hours_manager.html', { + 'form': form, + 'shift_id': shift_id, + 'volunteer_id': volunteer_id, + 'shift': shift, + 'volunteer_shift': volunteer_shift, + }) + + else: + messages.add_message( + self.request, messages.INFO, + 'End time should be greater than start time') + return render( + self.request, 'shift/edit_hours_manager.html', { + 'form': form, + 'shift_id': shift_id, + 'volunteer_id': volunteer_id, + 'shift': shift, + 'volunteer_shift': volunteer_shift, + }) + + except: + raise Http404 + + +class JobListView(AdministratorLoginRequiredMixin, + ListView): # Replaced by list_jobs + template_name = 'shift/list_jobs.html' + model_form = Job + + def get_queryset(self): + job = Job.objects.all().order_by('name') + return job + + +class ShiftListView(AdministratorLoginRequiredMixin, + TemplateView): # Replaced by list_shifts + template_name = 'shift/list_shifts.html' + + def get_context_data(self, **kwargs): + context = super(ShiftListView, self).get_context_data(**kwargs) + job_id = self.kwargs['job_id'] + context['shift_list'] = get_shifts_ordered_by_date(job_id) + return context + + +@login_required +def list_shifts_sign_up(request, job_id, volunteer_id): + if job_id: + job = get_job_by_id(job_id) + if job: + shift_list = [] + shift_list_all = get_shifts_with_open_slots_for_volunteer( + job_id, volunteer_id) + for shift in shift_list_all: + sdate = shift["date"] + today = date.today() + if sdate >= today: + shift_list.append(shift) + return render(request, 'shift/list_shifts_sign_up.html', { + 'shift_list': shift_list, + 'job': job, + 'volunteer_id': volunteer_id + }) + else: + raise Http404 + else: + raise Http404 + + +class ManageVolunteerShiftView(AdministratorLoginRequiredMixin, TemplateView): + template_name = 'shift/manage_volunteer_shifts.html' + + def get_context_data(self, **kwargs): + context = super(ManageVolunteerShiftView, self).get_context_data( + **kwargs) + volunteer_id = self.kwargs['volunteer_id'] + context['volunteer'] = get_volunteer_by_id(volunteer_id) + context['shift_list'] = get_unlogged_shifts_by_volunteer_id( + volunteer_id) + context['shift_list_with_hours'] = get_volunteer_shifts_with_hours( + volunteer_id) + return context + + +@login_required +def sign_up(request, shift_id, volunteer_id): + if shift_id: + shift = get_shift_by_id(shift_id) + if shift: + + user = request.user + admin = None + volunteer = None + + try: + admin = user.administrator + except ObjectDoesNotExist: + pass + try: + volunteer = user.volunteer + except ObjectDoesNotExist: + pass + + if not admin and not volunteer: + return HttpResponse(status=403) + + if volunteer: + if (int(volunteer.id) != int(volunteer_id)): + return HttpResponse(status=403) + + if request.method == 'POST': + try: + result = register(volunteer_id, shift_id) + if result == "IS_VALID": + if admin: + return HttpResponseRedirect( + reverse( + 'shift:manage_volunteer_shifts', + args=(volunteer_id, ))) + if volunteer: + return HttpResponseRedirect( + reverse( + 'shift:view_volunteer_shifts', + args=(volunteer_id, ))) + else: + return render(request, 'shift/sign_up_error.html', { + 'error_code': result + }) + except ObjectDoesNotExist: + raise Http404 + else: + return render(request, 'shift/sign_up.html', { + 'shift': shift, + 'volunteer_id': volunteer_id + }) + else: + raise Http404 + else: + raise Http404 + + +class ViewHoursView(LoginRequiredMixin, FormView, TemplateView): + template_name = 'shift/hours_list.html' + form_class = HoursForm + + @method_decorator(check_correct_volunteer) + @method_decorator(vol_id_check) + def dispatch(self, *args, **kwargs): + return super(ViewHoursView, self).dispatch(*args, **kwargs) + + def get_context_data(self, **kwargs): + context = super(ViewHoursView, self).get_context_data(**kwargs) + volunteer_id = self.kwargs['volunteer_id'] + context['volunteer'] = get_volunteer_by_id(volunteer_id) + context['volunteer_shift_list'] = get_volunteer_shifts_with_hours( + volunteer_id) + return context + + +@login_required +@check_correct_volunteer +@vol_id_check +def view_volunteer_shifts(request, volunteer_id): + shift_list = get_unlogged_shifts_by_volunteer_id(volunteer_id) + return render(request, 'shift/volunteer_shifts.html', { + 'shift_list': shift_list, + 'volunteer_id': volunteer_id, + }) + + +class VolunteerSearchView(AdministratorLoginRequiredMixin, FormView): + template_name = 'shift/volunteer_search.html' + form_class = SearchVolunteerForm + success_url = 'volunteer_list' + + def get_context_data(self, **kwargs): + context = super(VolunteerSearchView, self).get_context_data(**kwargs) + context['volunteer_list'] = get_all_volunteers() + context['has_searched'] = False + return context + + def form_valid(self, form): + first_name = form.cleaned_data['first_name'] + last_name = form.cleaned_data['last_name'] + city = form.cleaned_data['city'] + state = form.cleaned_data['state'] + country = form.cleaned_data['country'] + organization = form.cleaned_data['organization'] + + volunteer_list = search_volunteers(first_name, last_name, city, state, + country, organization) + return render(self.request, 'shift/volunteer_search.html', { + 'form': form, + 'has_searched': True, + 'volunteer_list': volunteer_list + }) + + +@login_required +def view_volunteers(request, shift_id): + user = request.user + admin = None + + try: + admin = user.administrator + except ObjectDoesNotExist: + pass + + # check that an admin is logged in + if not admin: + return render(request, 'vms/no_admin_rights.html') + else: + if shift_id: + shift = get_shift_by_id(shift_id) + if shift: + volunteer_list = get_volunteers_by_shift_id(shift_id) + logged_volunteer_list = get_logged_volunteers_by_shift_id( + shift_id) + slots_remaining = get_shift_slots_remaining(shift_id) + return render( + request, 'shift/list_volunteers.html', { + 'volunteer_list': volunteer_list, + 'shift': shift, + 'slots_remaining': slots_remaining, + 'logged_volunteer_list': logged_volunteer_list + }) + else: + raise Http404 + else: + raise Http404 diff --git a/vms/vms/utils.py b/vms/vms/utils.py index e7f5db9..49a5a9c 100644 --- a/vms/vms/utils.py +++ b/vms/vms/utils.py @@ -11,9 +11,10 @@ def check_correct_volunteer(func): @wraps(func) - def wrapped_view(request, volunteer_id): + def wrapped_view(request, **kwargs): req_volunteer = getattr(request.user, "volunteer", hasattr(request.user, "administrator")) + volunteer_id = kwargs['volunteer_id'] if not req_volunteer: raise Http404 elif req_volunteer is not True: @@ -35,9 +36,10 @@ def wrapped_view(request, volunteer_id): def check_correct_volunteer_shift_sign_up(func): @wraps(func) - def wrapped_view(request, volunteer_id): + def wrapped_view(request, **kwargs): req_volunteer = getattr(request.user, "volunteer", hasattr(request.user, "administrator")) + volunteer_id = kwargs['volunteer_id'] if req_volunteer is True: return func(request, volunteer_id=volunteer_id) if not req_volunteer: