Cleanup Respository
- Updated CodeIgniter - Removed unnecessary files. - Added custom translations. - Updated release-notes.txt for v1.1
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
src/configuration.php
|
12
build.bat
|
@ -1,12 +0,0 @@
|
||||||
:: Easy!Appointments
|
|
||||||
::
|
|
||||||
:: This scripts creates a new build for Easy!Appointments. This build
|
|
||||||
:: can be used for distributing a new version of the project.
|
|
||||||
TITLE Easy!Appointments
|
|
||||||
del /s/f/q "build\*.*"
|
|
||||||
for /f %%f in ('dir /ad /b "build"') do rd /s /q "build%f"
|
|
||||||
mkdir "build"
|
|
||||||
copy /y "release-notes.txt" "build\release-notes.txt"
|
|
||||||
xcopy /s/e/y "src" "build"
|
|
||||||
xcopy /y "build\configuration-sample.php" "build\configuration.php"
|
|
||||||
del "build\configuration-sample.php"
|
|
|
@ -1,329 +0,0 @@
|
||||||
-- phpMyAdmin SQL Dump
|
|
||||||
-- version 3.5.1
|
|
||||||
-- http://www.phpmyadmin.net
|
|
||||||
--
|
|
||||||
-- Φιλοξενητής: localhost
|
|
||||||
-- Χρόνος δημιουργίας: 24 Σεπ 2013 στις 11:03:51
|
|
||||||
-- Έκδοση διακομιστή: 5.5.24-log
|
|
||||||
-- Έκδοση PHP: 5.4.3
|
|
||||||
|
|
||||||
SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";
|
|
||||||
SET time_zone = "+00:00";
|
|
||||||
|
|
||||||
|
|
||||||
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
|
|
||||||
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
|
|
||||||
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
|
|
||||||
/*!40101 SET NAMES utf8 */;
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Βάση: `easy_appointments`
|
|
||||||
--
|
|
||||||
|
|
||||||
-- --------------------------------------------------------
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Δομή πίνακα για τον πίνακα `ea_appointments`
|
|
||||||
--
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS `ea_appointments` (
|
|
||||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
|
||||||
`book_datetime` datetime DEFAULT NULL,
|
|
||||||
`start_datetime` datetime DEFAULT NULL,
|
|
||||||
`end_datetime` datetime DEFAULT NULL,
|
|
||||||
`notes` text,
|
|
||||||
`hash` text,
|
|
||||||
`is_unavailable` tinyint(4) DEFAULT '0',
|
|
||||||
`id_users_provider` bigint(20) unsigned DEFAULT NULL,
|
|
||||||
`id_users_customer` bigint(20) unsigned DEFAULT NULL,
|
|
||||||
`id_services` bigint(20) unsigned DEFAULT NULL,
|
|
||||||
`id_google_calendar` text,
|
|
||||||
PRIMARY KEY (`id`),
|
|
||||||
KEY `id_users_customer` (`id_users_customer`),
|
|
||||||
KEY `id_services` (`id_services`),
|
|
||||||
KEY `id_users_provider` (`id_users_provider`)
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=42 ;
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Άδειασμα δεδομένων του πίνακα `ea_appointments`
|
|
||||||
--
|
|
||||||
|
|
||||||
INSERT INTO `ea_appointments` (`id`, `book_datetime`, `start_datetime`, `end_datetime`, `notes`, `hash`, `is_unavailable`, `id_users_provider`, `id_users_customer`, `id_services`, `id_google_calendar`) VALUES
|
|
||||||
(21, '2013-09-13 12:02:18', '2013-09-13 15:00:00', '2013-09-13 17:00:00', '', 'be278cf3c1d617fc372d89d75d5fd26d', 0, 2, 21, 4, 'e2c7abe3eket7ip9c58lllt3c8'),
|
|
||||||
(37, '2013-09-13 13:47:54', '2013-09-14 11:30:00', '2013-09-14 13:30:00', 'Γυμναστήριο ', '3ace1513fdf92a4983b7ae719a8475b5', 1, 2, NULL, NULL, 'cqm0t14p50d0917ghkirtruuno'),
|
|
||||||
(38, '2013-09-13 13:47:54', '2013-09-14 15:00:00', '2013-09-14 18:00:00', 'Ε!Α ', '3ace1513fdf92a4983b7ae719a8475b5', 1, 2, NULL, NULL, 'vs0btdvi34t73rvkeubh77ln40'),
|
|
||||||
(39, '2013-09-13 15:39:44', '2013-09-13 17:00:00', '2013-09-13 17:20:00', 'This is a test appt.', '6fd60f567310511d8f2fb4ff4c787d5e', 0, 2, 22, 3, NULL),
|
|
||||||
(40, '2013-09-13 15:50:14', '2013-09-14 10:00:00', '2013-09-14 11:00:00', 'heart decease', '39b81301e5bb1a82f77bd23d07ec63ce', 0, 4, 23, 2, NULL),
|
|
||||||
(41, '2013-09-23 17:04:53', '2013-09-24 09:45:00', '2013-09-24 10:15:00', '', '4c782e7af14a98e03657cc64c9a4fe61', 0, 25, 26, 4, NULL);
|
|
||||||
|
|
||||||
-- --------------------------------------------------------
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Δομή πίνακα για τον πίνακα `ea_roles`
|
|
||||||
--
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS `ea_roles` (
|
|
||||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
|
||||||
`name` varchar(256) DEFAULT NULL,
|
|
||||||
`slug` varchar(256) DEFAULT NULL,
|
|
||||||
`is_admin` tinyint(4) DEFAULT NULL COMMENT '0',
|
|
||||||
`appointments` int(4) DEFAULT NULL COMMENT '0',
|
|
||||||
`customers` int(4) DEFAULT NULL COMMENT '0',
|
|
||||||
`services` int(4) DEFAULT NULL COMMENT '0',
|
|
||||||
`users` int(4) DEFAULT NULL COMMENT '0',
|
|
||||||
`system_settings` int(4) DEFAULT NULL COMMENT '0',
|
|
||||||
`user_settings` int(11) DEFAULT NULL,
|
|
||||||
PRIMARY KEY (`id`)
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=5 ;
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Άδειασμα δεδομένων του πίνακα `ea_roles`
|
|
||||||
--
|
|
||||||
|
|
||||||
INSERT INTO `ea_roles` (`id`, `name`, `slug`, `is_admin`, `appointments`, `customers`, `services`, `users`, `system_settings`, `user_settings`) VALUES
|
|
||||||
(1, 'Administrator', 'admin', 1, 15, 15, 15, 15, 15, NULL),
|
|
||||||
(2, 'Provider', 'provider', 0, 15, 15, 0, 0, 0, NULL),
|
|
||||||
(3, 'Customer', 'customer', 0, 0, 0, 0, 0, 0, NULL),
|
|
||||||
(4, 'Secretary', 'secretary', 0, 15, 15, 0, 0, 15, NULL);
|
|
||||||
|
|
||||||
-- --------------------------------------------------------
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Δομή πίνακα για τον πίνακα `ea_secretaries_providers`
|
|
||||||
--
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS `ea_secretaries_providers` (
|
|
||||||
`id_users_secretary` bigint(20) unsigned NOT NULL,
|
|
||||||
`id_users_provider` bigint(20) unsigned NOT NULL,
|
|
||||||
PRIMARY KEY (`id_users_secretary`,`id_users_provider`),
|
|
||||||
KEY `fk_ea_secretaries_providers_1` (`id_users_secretary`),
|
|
||||||
KEY `fk_ea_secretaries_providers_2` (`id_users_provider`)
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Άδειασμα δεδομένων του πίνακα `ea_secretaries_providers`
|
|
||||||
--
|
|
||||||
|
|
||||||
INSERT INTO `ea_secretaries_providers` (`id_users_secretary`, `id_users_provider`) VALUES
|
|
||||||
(20, 2),
|
|
||||||
(20, 3);
|
|
||||||
|
|
||||||
-- --------------------------------------------------------
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Δομή πίνακα για τον πίνακα `ea_services`
|
|
||||||
--
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS `ea_services` (
|
|
||||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
|
||||||
`name` varchar(256) DEFAULT NULL,
|
|
||||||
`duration` int(11) DEFAULT NULL,
|
|
||||||
`price` decimal(10,2) DEFAULT NULL,
|
|
||||||
`currency` varchar(32) DEFAULT NULL,
|
|
||||||
`description` text,
|
|
||||||
`id_service_categories` bigint(20) unsigned DEFAULT NULL,
|
|
||||||
PRIMARY KEY (`id`),
|
|
||||||
KEY `id_service_categories` (`id_service_categories`)
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=5 ;
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Άδειασμα δεδομένων του πίνακα `ea_services`
|
|
||||||
--
|
|
||||||
|
|
||||||
INSERT INTO `ea_services` (`id`, `name`, `duration`, `price`, `currency`, `description`, `id_service_categories`) VALUES
|
|
||||||
(2, 'Heart Examination', 30, '40.00', 'Euro', 'Checkup for heart problems.', NULL),
|
|
||||||
(3, 'Neurological Examination', 20, '35.00', 'Euro', 'Neurological tests for the patient.', NULL),
|
|
||||||
(4, 'General Examination', 30, '30.00', 'Euro', 'General patient examination. Includes blood, pressure and eyes tests.', 2);
|
|
||||||
|
|
||||||
-- --------------------------------------------------------
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Δομή πίνακα για τον πίνακα `ea_services_providers`
|
|
||||||
--
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS `ea_services_providers` (
|
|
||||||
`id_users` bigint(20) unsigned NOT NULL,
|
|
||||||
`id_services` bigint(20) unsigned NOT NULL,
|
|
||||||
PRIMARY KEY (`id_users`,`id_services`),
|
|
||||||
KEY `id_services` (`id_services`)
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Άδειασμα δεδομένων του πίνακα `ea_services_providers`
|
|
||||||
--
|
|
||||||
|
|
||||||
INSERT INTO `ea_services_providers` (`id_users`, `id_services`) VALUES
|
|
||||||
(3, 2),
|
|
||||||
(4, 2),
|
|
||||||
(2, 3),
|
|
||||||
(3, 3),
|
|
||||||
(2, 4),
|
|
||||||
(25, 4);
|
|
||||||
|
|
||||||
-- --------------------------------------------------------
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Δομή πίνακα για τον πίνακα `ea_service_categories`
|
|
||||||
--
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS `ea_service_categories` (
|
|
||||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
|
||||||
`name` varchar(256) DEFAULT NULL,
|
|
||||||
`description` text,
|
|
||||||
PRIMARY KEY (`id`)
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=8 ;
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Άδειασμα δεδομένων του πίνακα `ea_service_categories`
|
|
||||||
--
|
|
||||||
|
|
||||||
INSERT INTO `ea_service_categories` (`id`, `name`, `description`) VALUES
|
|
||||||
(2, 'General Services', 'Contains the general services of our company.'),
|
|
||||||
(5, 'test1', 'test1'),
|
|
||||||
(7, 'test2', 'test2');
|
|
||||||
|
|
||||||
-- --------------------------------------------------------
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Δομή πίνακα για τον πίνακα `ea_settings`
|
|
||||||
--
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS `ea_settings` (
|
|
||||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
|
||||||
`name` varchar(512) DEFAULT NULL,
|
|
||||||
`value` longtext,
|
|
||||||
PRIMARY KEY (`id`)
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=16 ;
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Άδειασμα δεδομένων του πίνακα `ea_settings`
|
|
||||||
--
|
|
||||||
|
|
||||||
INSERT INTO `ea_settings` (`id`, `name`, `value`) VALUES
|
|
||||||
(1, 'company_name', 'Easy!Appointmnets & Co'),
|
|
||||||
(2, 'company_working_plan', '{"monday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"tuesday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"wednesday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"thursday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"friday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"saturday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"sunday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]}}'),
|
|
||||||
(3, 'company_email', 'info@alextselegidis.com'),
|
|
||||||
(8, 'company_link', 'http://easyappointments.org'),
|
|
||||||
(9, 'book_advance_timeout', '30'),
|
|
||||||
(15, NULL, NULL);
|
|
||||||
|
|
||||||
-- --------------------------------------------------------
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Δομή πίνακα για τον πίνακα `ea_users`
|
|
||||||
--
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS `ea_users` (
|
|
||||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
|
||||||
`first_name` varchar(256) DEFAULT NULL,
|
|
||||||
`last_name` varchar(512) DEFAULT NULL,
|
|
||||||
`email` varchar(512) DEFAULT NULL,
|
|
||||||
`mobile_number` varchar(128) DEFAULT NULL,
|
|
||||||
`phone_number` varchar(128) DEFAULT NULL,
|
|
||||||
`address` varchar(256) DEFAULT NULL,
|
|
||||||
`city` varchar(256) DEFAULT NULL,
|
|
||||||
`state` varchar(128) DEFAULT NULL,
|
|
||||||
`zip_code` varchar(64) DEFAULT NULL,
|
|
||||||
`notes` text,
|
|
||||||
`id_roles` bigint(20) unsigned NOT NULL,
|
|
||||||
PRIMARY KEY (`id`),
|
|
||||||
KEY `id_roles` (`id_roles`)
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=27 ;
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Άδειασμα δεδομένων του πίνακα `ea_users`
|
|
||||||
--
|
|
||||||
|
|
||||||
INSERT INTO `ea_users` (`id`, `first_name`, `last_name`, `email`, `mobile_number`, `phone_number`, `address`, `city`, `state`, `zip_code`, `notes`, `id_roles`) VALUES
|
|
||||||
(2, 'Ned', 'Janger', 'alextselegidis@gmail.com', '659875666', '785448465', 'Kloesel', 'Berlin', '', '23980', '', 2),
|
|
||||||
(3, 'Urlich', 'Setzel', 'u.setzel@piorin.com', '23908252398', '20923798723', 'Groundliche Str. 23', 'Munich', 'Bayern', '86895', '', 2),
|
|
||||||
(4, 'Brandon', 'Clod', 'b.clod@besters.org', '239072439', '858754487', 'Wellin Str 8', 'Plymouth', '', '20940', '', 2),
|
|
||||||
(18, 'Tod', 'Cliffer', 'info@alextselegidis.com', '987568857', '875986878', 'Yourd Str 98', 'Blackpool', 'MyState', '85874', 'This is a test admin record used for testing the project. All the data are not real.', 1),
|
|
||||||
(20, 'Sonia', 'Sterling', 's.sterling@reo.com', '584256658', '4265462587', '', '', '', '', '', 4),
|
|
||||||
(21, 'Alex', 'Tselegidis', 'info@alextselegidis.com', NULL, '98765465712', '', '', NULL, '', '', 3),
|
|
||||||
(22, 'John', 'Doe', 'john.doe@oizent.com', NULL, '8757595445', 'Orizend 51', 'London', NULL, '56648', 'Test customer record.', 3),
|
|
||||||
(23, 'James', 'Goern', 'james.goern@softiner.com', NULL, '98654869544', 'Ureklin 09', 'New York', NULL, '56987', NULL, 3),
|
|
||||||
(24, 'test', 'test', 'test@test.com', '233252325', '234523342', 'test', 'test', '', '', '', 1),
|
|
||||||
(25, 'Jason', 'Brandon', 'j.brandon@solyell.uk', '7899875789', '7854789897', 'Hilton Str. 52', 'Michigan', '', '87786', 'This is a test provider. All data are fictional.', 2),
|
|
||||||
(26, 'John', 'Doe', 'j.doe@doens.com', NULL, '897987657', '', '', NULL, '', NULL, 3);
|
|
||||||
|
|
||||||
-- --------------------------------------------------------
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Δομή πίνακα για τον πίνακα `ea_user_settings`
|
|
||||||
--
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS `ea_user_settings` (
|
|
||||||
`id_users` bigint(20) unsigned NOT NULL,
|
|
||||||
`username` varchar(256) DEFAULT NULL,
|
|
||||||
`password` varchar(512) DEFAULT NULL,
|
|
||||||
`salt` varchar(512) DEFAULT NULL,
|
|
||||||
`working_plan` text,
|
|
||||||
`notifications` tinyint(4) DEFAULT '0',
|
|
||||||
`google_sync` tinyint(4) DEFAULT '0',
|
|
||||||
`google_token` text,
|
|
||||||
`sync_past_days` int(11) DEFAULT '5',
|
|
||||||
`sync_future_days` int(11) DEFAULT '5',
|
|
||||||
PRIMARY KEY (`id_users`)
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Άδειασμα δεδομένων του πίνακα `ea_user_settings`
|
|
||||||
--
|
|
||||||
|
|
||||||
INSERT INTO `ea_user_settings` (`id_users`, `username`, `password`, `salt`, `working_plan`, `notifications`, `google_sync`, `google_token`, `sync_past_days`, `sync_future_days`) VALUES
|
|
||||||
(2, 'ned.janger', '6ad76c5daab92f2aaf9f9d725cb72bc2774fdb4ac2172828a8f1c6aa69e9b0d1', 'edd27f8204a0cc47c60a3cd031fe03211be2561c76b334678e0f982ef582bf6e', '{"monday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"tuesday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"wednesday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"thursday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"friday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"saturday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"sunday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]}}', 1, 0, NULL, 5, 5),
|
|
||||||
(3, 'u.setzel', 'f00e1e6f3780859b40645be7ff8e91878ea2679eb62fbc45a8bff1243338b741', '7f8231dd21df341c651522e4091637e6a93d160decb6a7a99bd08a5dc5d947c8', '{"monday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"tuesday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"wednesday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"thursday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"friday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"saturday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"sunday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]}}', 1, 0, NULL, 5, 5),
|
|
||||||
(4, 'b.clod', '811acf5c450e0eb2866a17cdc3701a0b1fddb98ea2065e91259e8e6ce9b678b6', 'edd27f8204a0cc47c60a3cd031fe03211be2561c76b334678e0f982ef582bf6e', '{"monday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"tuesday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"wednesday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"thursday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"friday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"saturday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"sunday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]}}', 0, 0, NULL, 5, 5),
|
|
||||||
(18, 'admin', '9e81360f0a631fe7e49e9d051b05c581a0f17575ca043a340be4441e166de821', 'd6ac3bfb4e6d9f82ec54e606852a9afbe8697696cddd28f30423eddf98762f41', NULL, 0, 0, NULL, 5, 5),
|
|
||||||
(20, 's.sterling', '8746aff0a416b63e71046d6a6adc6e2fd9de4a1cf4de0281e5b5f60ba8ae4451', 'edd27f8204a0cc47c60a3cd031fe03211be2561c76b334678e0f982ef582bf6e', NULL, 0, 0, NULL, 5, 5),
|
|
||||||
(24, 'test', 'd1dce587f7eefdb93adceb4e8903d72036bf97d37482b9c7b1d5f08353d061f3', 'd6ac3bfb4e6d9f82ec54e606852a9afbe8697696cddd28f30423eddf98762f41', NULL, 0, 0, NULL, 5, 5),
|
|
||||||
(25, 'j.brandon', 'dc93d098ccbcaa871e4adcc2dd770d71f6fca7a24dbd635e00006b5075dc2db1', '7f8231dd21df341c651522e4091637e6a93d160decb6a7a99bd08a5dc5d947c8', '{"monday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"tuesday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"wednesday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"thursday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"friday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"saturday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"sunday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]}}', 1, 0, NULL, 5, 5);
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Περιορισμοί για άχρηστους πίνακες
|
|
||||||
--
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Περιορισμοί για πίνακα `ea_appointments`
|
|
||||||
--
|
|
||||||
ALTER TABLE `ea_appointments`
|
|
||||||
ADD CONSTRAINT `ea_appointments_ibfk_2` FOREIGN KEY (`id_users_customer`) REFERENCES `ea_users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
|
|
||||||
ADD CONSTRAINT `ea_appointments_ibfk_3` FOREIGN KEY (`id_services`) REFERENCES `ea_services` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
|
|
||||||
ADD CONSTRAINT `ea_appointments_ibfk_4` FOREIGN KEY (`id_users_provider`) REFERENCES `ea_users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Περιορισμοί για πίνακα `ea_secretaries_providers`
|
|
||||||
--
|
|
||||||
ALTER TABLE `ea_secretaries_providers`
|
|
||||||
ADD CONSTRAINT `fk_ea_secretaries_providers_1` FOREIGN KEY (`id_users_secretary`) REFERENCES `ea_users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
|
|
||||||
ADD CONSTRAINT `fk_ea_secretaries_providers_2` FOREIGN KEY (`id_users_provider`) REFERENCES `ea_users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Περιορισμοί για πίνακα `ea_services`
|
|
||||||
--
|
|
||||||
ALTER TABLE `ea_services`
|
|
||||||
ADD CONSTRAINT `ea_services_ibfk_1` FOREIGN KEY (`id_service_categories`) REFERENCES `ea_service_categories` (`id`) ON DELETE SET NULL ON UPDATE CASCADE;
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Περιορισμοί για πίνακα `ea_services_providers`
|
|
||||||
--
|
|
||||||
ALTER TABLE `ea_services_providers`
|
|
||||||
ADD CONSTRAINT `ea_services_providers_ibfk_1` FOREIGN KEY (`id_users`) REFERENCES `ea_users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
|
|
||||||
ADD CONSTRAINT `ea_services_providers_ibfk_2` FOREIGN KEY (`id_services`) REFERENCES `ea_services` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Περιορισμοί για πίνακα `ea_users`
|
|
||||||
--
|
|
||||||
ALTER TABLE `ea_users`
|
|
||||||
ADD CONSTRAINT `ea_users_ibfk_1` FOREIGN KEY (`id_roles`) REFERENCES `ea_roles` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Περιορισμοί για πίνακα `ea_user_settings`
|
|
||||||
--
|
|
||||||
ALTER TABLE `ea_user_settings`
|
|
||||||
ADD CONSTRAINT `ea_user_settings_ibfk_1` FOREIGN KEY (`id_users`) REFERENCES `ea_users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;
|
|
||||||
|
|
||||||
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
|
|
||||||
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
|
|
||||||
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
|
|
@ -1,17 +0,0 @@
|
||||||
:: Easy!Appointments
|
|
||||||
::
|
|
||||||
:: This script generates the code documentation of the system
|
|
||||||
:: using the jsdoc and apigen tools. In order to run properly
|
|
||||||
:: the system should have Java and ApiGen installed already.
|
|
||||||
::
|
|
||||||
:: THIS SCRIPT RUNS ONLY ON WINDOWS. YOU MIGHT NEED TO CHANGE
|
|
||||||
:: THE APIGEN SCRIPT PATH TO WHERE YOUR INSTALLATION EXISTS.
|
|
||||||
::
|
|
||||||
:: You might also need to change the mermory_limit setting on your
|
|
||||||
:: php.ini file to successfully generate the php documentation.
|
|
||||||
::@echo off
|
|
||||||
TITLE Easy!Appointments
|
|
||||||
DEL "js\*.*" /Q
|
|
||||||
DEL "php\*.*" /Q
|
|
||||||
CALL ..\..\rsc\scripts\jsdoc\jsdoc ..\..\src\assets\js -d js
|
|
||||||
CALL C:\wamp\bin\php\php5.4.3\apigen --source ..\..\src\application\controllers --source ..\..\src\application\models --destination php
|
|
|
@ -1,51 +0,0 @@
|
||||||
:: ===============================================
|
|
||||||
:: GENERATES THE EASY!APPOINTMENTS THESIS DOCUMENT
|
|
||||||
:: ===============================================
|
|
||||||
|
|
||||||
:: Run Cleanup
|
|
||||||
call:cleanupq
|
|
||||||
|
|
||||||
:: Run XeLaTex on main file.
|
|
||||||
xelatex thesis.tex --quiet
|
|
||||||
biber thesis --quiet
|
|
||||||
|
|
||||||
:: If you are using multibib the following will run bibtex on all aux files
|
|
||||||
:: FOR /R . %%G IN (*.aux) DO bibtex %%G
|
|
||||||
xelatex thesis.tex --quiet
|
|
||||||
xelatex thesis.tex --quiet
|
|
||||||
|
|
||||||
:: Run Cleanup
|
|
||||||
call:cleanup
|
|
||||||
|
|
||||||
:: Open PDF (Script updated based on comments by 'menfeser'
|
|
||||||
:: START "" "C:\Program Files\Adobe\Reader 9.0\Reader\AcroRd32.exe" %2.pdf
|
|
||||||
START "" thesis.pdf
|
|
||||||
|
|
||||||
:: Cleanup Function
|
|
||||||
:cleanup
|
|
||||||
del *.log
|
|
||||||
del *.dvi
|
|
||||||
del *.aux
|
|
||||||
del *.bbl
|
|
||||||
del *.blg
|
|
||||||
del *.brf
|
|
||||||
del *.out
|
|
||||||
del *.log
|
|
||||||
del *.bcf
|
|
||||||
del *.xml
|
|
||||||
del *.toc
|
|
||||||
del *.lof
|
|
||||||
|
|
||||||
del includes\*.log
|
|
||||||
del includes\*.dvi
|
|
||||||
del includes\*.aux
|
|
||||||
del includes\*.bbl
|
|
||||||
del includes\*.blg
|
|
||||||
del includes\*.brf
|
|
||||||
del includes\*.out
|
|
||||||
del includes\*.log
|
|
||||||
del includes\*.bcf
|
|
||||||
del includes\*.xml
|
|
||||||
del includes\*.toc
|
|
||||||
|
|
||||||
goto:eof
|
|
|
@ -1,36 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
|
|
||||||
## ===============================================
|
|
||||||
## GENERATES THE EASY!APPOINTMENTS THESIS DOCUMENT
|
|
||||||
## ===============================================
|
|
||||||
|
|
||||||
clear
|
|
||||||
xelatex --output-format=pdf thesis.tex --quiet
|
|
||||||
bibtex thesis.tex
|
|
||||||
xelatex --output-format=pdf thesis.tex --quiet
|
|
||||||
|
|
||||||
rm *.log
|
|
||||||
rm *.dvi
|
|
||||||
rm *.aux
|
|
||||||
rm *.bbl
|
|
||||||
rm *.blg
|
|
||||||
rm *.brf
|
|
||||||
rm *.out
|
|
||||||
rm *.log
|
|
||||||
rm *.bcf
|
|
||||||
rm *.xml
|
|
||||||
rm *.toc
|
|
||||||
|
|
||||||
rm includes\*.log
|
|
||||||
rm includes\*.dvi
|
|
||||||
rm includes\*.aux
|
|
||||||
rm includes\*.bbl
|
|
||||||
rm includes\*.blg
|
|
||||||
rm includes\*.brf
|
|
||||||
rm includes\*.out
|
|
||||||
rm includes\*.log
|
|
||||||
rm includes\*.bcf
|
|
||||||
rm includes\*.xml
|
|
||||||
rm includes\*.toc
|
|
||||||
|
|
||||||
echo "Process Ended"
|
|
|
@ -1 +0,0 @@
|
||||||
<mxGraphModel dx="800" dy="800" grid="1" guides="1" tooltips="1" connect="1" fold="1" page="1" pageScale="1" pageWidth="826" pageHeight="1169" style="default-style2"><root><mxCell id="0"/><mxCell id="1" parent="0"/><mxCell id="2" value="" style="ellipse;shape=startState;fillColor=#000000;strokeColor=#ff0000;" vertex="1" parent="1"><mxGeometry x="122.5" y="20" width="30" height="30" as="geometry"/></mxCell><mxCell id="3" value="" style="edgeStyle=elbowEdgeStyle;elbow=horizontal;verticalAlign=bottom;endArrow=open;endSize=8;strokeColor=#ff0000;entryX=0.5;entryY=0" edge="1" source="2" parent="1" target="4"><mxGeometry x="122.5" y="20" as="geometry"><mxPoint x="137.5" y="90" as="targetPoint"/></mxGeometry></mxCell><mxCell id="4" value="Λήψη Πλάνου Εργασίας
& Καταχωρημένων Ραντεβού" style="rounded=1;arcSize=40;fillColor=#ffffc0;strokeColor=#ff0000;" vertex="1" parent="1"><mxGeometry x="55" y="76" width="165" height="40" as="geometry"/></mxCell><mxCell id="5" value="" style="edgeStyle=elbowEdgeStyle;elbow=horizontal;verticalAlign=bottom;endArrow=open;endSize=8;strokeColor=#ff0000;entryX=0.5;entryY=0" edge="1" parent="1" target="6"><mxGeometry x="77" y="76" as="geometry"><mxPoint x="137" y="156" as="targetPoint"/><mxPoint x="137" y="116" as="sourcePoint"/></mxGeometry></mxCell><mxCell id="6" value="Διάσταση Πλάνου Εργασίας
Από Διαλείμματα" style="rounded=1;arcSize=40;fillColor=#ffffc0;strokeColor=#ff0000;" vertex="1" parent="1"><mxGeometry x="55" y="145" width="165" height="40" as="geometry"/></mxCell><mxCell id="7" value="" style="edgeStyle=elbowEdgeStyle;elbow=horizontal;verticalAlign=bottom;endArrow=open;endSize=8;strokeColor=#ff0000;entryX=0.5;entryY=0" edge="1" parent="1" target="10"><mxGeometry x="77" y="145" as="geometry"><mxPoint x="137" y="225" as="targetPoint"/><mxPoint x="137" y="185" as="sourcePoint"/></mxGeometry></mxCell><mxCell id="10" value="Διάσταση Πλάνου Εργασίας
Από Καταχωρημένα Ραντεβού" style="rounded=1;arcSize=40;fillColor=#ffffc0;strokeColor=#ff0000;" vertex="1" parent="1"><mxGeometry x="55" y="214" width="165" height="40" as="geometry"/></mxCell><mxCell id="11" value="" style="edgeStyle=elbowEdgeStyle;elbow=horizontal;verticalAlign=bottom;endArrow=open;endSize=8;strokeColor=#ff0000;entryX=0.5;entryY=0" edge="1" parent="1" target="12"><mxGeometry x="77" y="214" as="geometry"><mxPoint x="137" y="294" as="targetPoint"/><mxPoint x="137" y="254" as="sourcePoint"/></mxGeometry></mxCell><mxCell id="12" value="Υπολογισμός Διαθέσιμων
Ωρών Ραντεβού" style="rounded=1;arcSize=40;fillColor=#ffffc0;strokeColor=#ff0000;" vertex="1" parent="1"><mxGeometry x="55" y="284" width="165" height="40" as="geometry"/></mxCell><mxCell id="13" value="" style="edgeStyle=elbowEdgeStyle;elbow=horizontal;verticalAlign=bottom;endArrow=open;endSize=8;strokeColor=#ff0000;entryX=0.5;entryY=0" edge="1" parent="1" target="14"><mxGeometry x="77" y="284" as="geometry"><mxPoint x="137" y="364" as="targetPoint"/><mxPoint x="137" y="324" as="sourcePoint"/></mxGeometry></mxCell><mxCell id="14" value="" style="ellipse;shape=endState;fillColor=#000000;strokeColor=#ff0000" vertex="1" parent="1"><mxGeometry x="122.5" y="352" width="30" height="30" as="geometry"/></mxCell></root></mxGraphModel>
|
|
|
@ -1 +0,0 @@
|
||||||
<mxGraphModel dx="800" dy="800" grid="1" guides="1" tooltips="1" connect="1" fold="1" page="1" pageScale="1" pageWidth="826" pageHeight="1169" style="default-style2"><root><mxCell id="0"/><mxCell id="1" parent="0"/><mxCell id="4" value="<p style="margin: 0px; margin-top: 4px; text-align: center;"><strong>BackendSettings</strong></p><hr /><p style="margin: 0px; margin-left: 4px;">+ wp: WorkingPlan</p><p style="margin: 0px; margin-left: 4px;">+ settings: SettingsHelper</p><hr /><p style="margin: 0px; margin-left: 4px;">+ initialize(): void</p><p style="margin: 0px; margin-left: 4px;">+ bindEventHandlers(): void</p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=12;fontFamily=Helvetica;html=1" vertex="1" parent="1"><mxGeometry x="70" y="100" width="160" height="140" as="geometry"/></mxCell><mxCell id="5" value="<p style="margin: 0px; margin-top: 4px; text-align: center;"><em>&lt;&lt;Interface&gt;&gt;</em><br /><strong>SettingsHelper</strong></p><hr /><p>&nbsp;</p><hr /><p style="margin: 0px; margin-left: 4px;">+ save(): void<br /> + get(): object<br /> + validate(): bool</p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=12;fontFamily=Helvetica;html=1" vertex="1" parent="1"><mxGeometry x="337.5" y="100" width="170" height="140" as="geometry"/></mxCell><mxCell id="6" value="<p style="margin: 0px; margin-top: 4px; text-align: center;"><strong>UserSettings</strong></p><hr /><div style="height: 2px;">&nbsp;</div><hr />" style="verticalAlign=top;align=left;overflow=fill;fontSize=12;fontFamily=Helvetica;html=1" vertex="1" parent="1"><mxGeometry x="280" y="310" width="140" height="60" as="geometry"/></mxCell><mxCell id="7" value="<p style="margin: 0px; margin-top: 4px; text-align: center;"><strong>SystemSettings</strong></p><hr /><div style="height: 2px;">&nbsp;</div><hr />" style="verticalAlign=top;align=left;overflow=fill;fontSize=12;fontFamily=Helvetica;html=1" vertex="1" parent="1"><mxGeometry x="432.5" y="310" width="140" height="60" as="geometry"/></mxCell><mxCell id="8" value="" style="endArrow=block;startArrow=none;endFill=0;startFill=0;exitX=0.5;exitY=0;dashed=1" edge="1" parent="1" target="5"><mxGeometry x="17.5" as="geometry"><mxPoint x="347.5" y="310" as="sourcePoint"/><mxPoint x="177.5" as="targetPoint"/></mxGeometry></mxCell><mxCell id="9" value="" style="endArrow=block;startArrow=none;endFill=0;startFill=0;entryX=0.75;entryY=1;dashed=1" edge="1" parent="1" source="7" target="5"><mxGeometry x="17.5" as="geometry"><mxPoint x="17.5" as="sourcePoint"/><mxPoint x="177.5" as="targetPoint"/></mxGeometry></mxCell><mxCell id="11" value="" style="endArrow=none;startArrow=diamondThin;endFill=0;startFill=1;exitX=1;exitY=0.25;entryX=0;entryY=0.25" edge="1" parent="1" source="4" target="5"><mxGeometry as="geometry"><mxPoint as="sourcePoint"/><mxPoint x="160" as="targetPoint"/></mxGeometry></mxCell><mxCell id="12" value="<p style="margin: 0px; margin-top: 4px; text-align: center;"><strong>WorkingPlan</strong></p><hr /><p style="margin: 0px; margin-left: 4px;">+ enableCancel: bool</p><p style="margin: 0px; margin-left: 4px;">+ enableSubmit: bool</p><hr /><p style="margin: 0px; margin-left: 4px;">+ setup(): void</p><p style="margin: 0px; margin-left: 4px;">+ bindEventHandlers(): void</p><p style="margin: 0px; margin-left: 4px;">+ editableBreakDay(): void</p><p style="margin: 0px; margin-left: 4px;">+ editableBreakTime(): void</p><p style="margin: 0px; margin-left: 4px;">+ get(): void</p><p style="margin: 0px; margin-left: 4px;">+ timepickers(): void</p>" style="verticalAlign=top;align=left;overflow=fill;fontSize=12;fontFamily=Helvetica;html=1" vertex="1" parent="1"><mxGeometry x="65" y="310" width="170" height="180" as="geometry"/></mxCell><mxCell id="16" value="" style="endArrow=diamondThin;startArrow=none;endFill=1;startFill=0;exitX=0.5;exitY=0;entryX=0.5;entryY=1" edge="1" parent="1" source="12" target="4"><mxGeometry as="geometry"><mxPoint as="sourcePoint"/><mxPoint x="160" as="targetPoint"/></mxGeometry></mxCell></root></mxGraphModel>
|
|
|
@ -1 +0,0 @@
|
||||||
<mxGraphModel dx="800" dy="800" grid="1" guides="1" tooltips="1" connect="1" fold="1" page="1" pageScale="1" pageWidth="826" pageHeight="1169" style="default-style2"><root><mxCell id="0"/><mxCell id="1" parent="0"/><mxCell id="5" value="Κλείνει" style="rhombus;whiteSpace=wrap" vertex="1" parent="1"><mxGeometry x="175" y="160" width="80" height="80" as="geometry"/></mxCell><mxCell id="8" value="Υπηρεσία" style="ellipse;shape=doubleEllipse;whiteSpace=wrap" vertex="1" parent="1"><mxGeometry x="290" y="150" width="150" height="50" as="geometry"/></mxCell><mxCell id="9" value="Πάροχος" style="ellipse;shape=doubleEllipse;whiteSpace=wrap" vertex="1" parent="1"><mxGeometry x="290" y="210" width="150" height="50" as="geometry"/></mxCell><mxCell id="10" value="" style="endArrow=none" edge="1" parent="1" source="8" target="5"><mxGeometry relative="1" as="geometry"/></mxCell><mxCell id="11" value="" style="endArrow=none" edge="1" parent="1" source="9" target="5"><mxGeometry relative="1" as="geometry"/></mxCell><mxCell id="12" value="Πελάτης" style="whiteSpace=wrap" vertex="1" parent="1"><mxGeometry x="155" y="60" width="120" height="40" as="geometry"/></mxCell><mxCell id="13" value="" style="endArrow=none" edge="1" parent="1" source="12" target="5"><mxGeometry relative="1" as="geometry"/></mxCell><mxCell id="15" value="Ραντεβού" style="whiteSpace=wrap" vertex="1" parent="1"><mxGeometry x="155" y="320" width="120" height="40" as="geometry"/></mxCell><mxCell id="16" value="" style="endArrow=none" edge="1" parent="1" source="15" target="5"><mxGeometry relative="1" as="geometry"/></mxCell><mxCell id="17" value="Πάροχος" style="whiteSpace=wrap" vertex="1" parent="1"><mxGeometry x="460" y="320" width="120" height="40" as="geometry"/></mxCell><mxCell id="18" value="Έχει" style="rhombus;whiteSpace=wrap" vertex="1" parent="1"><mxGeometry x="325" y="300" width="80" height="80" as="geometry"/></mxCell><mxCell id="19" value="" style="endArrow=none" edge="1" parent="1" source="18" target="17"><mxGeometry relative="1" as="geometry"/></mxCell><mxCell id="20" value="" style="endArrow=none" edge="1" parent="1" source="18" target="15"><mxGeometry relative="1" as="geometry"/></mxCell><mxCell id="21" value="1" style="text;spacingTop=-5;" vertex="1" parent="1"><mxGeometry x="425" y="350" width="30" height="20" as="geometry"/></mxCell><mxCell id="24" value="*" style="text;spacingTop=-5;" vertex="1" parent="1"><mxGeometry x="290" y="350" width="30" height="20" as="geometry"/></mxCell><mxCell id="25" value="1" style="text;spacingTop=-5;" vertex="1" parent="1"><mxGeometry x="225" y="110" width="30" height="20" as="geometry"/></mxCell><mxCell id="26" value="*" style="text;spacingTop=-5;" vertex="1" parent="1"><mxGeometry x="225" y="290" width="30" height="20" as="geometry"/></mxCell><mxCell id="27" value="Γραμματέας" style="whiteSpace=wrap" vertex="1" parent="1"><mxGeometry x="460" y="570" width="120" height="40" as="geometry"/></mxCell><mxCell id="28" value="Διαχειρίζεται" style="rhombus;whiteSpace=wrap" vertex="1" parent="1"><mxGeometry x="480" y="430" width="80" height="80" as="geometry"/></mxCell><mxCell id="29" value="" style="endArrow=none" edge="1" parent="1" source="28" target="17"><mxGeometry relative="1" as="geometry"/></mxCell><mxCell id="30" value="" style="endArrow=none" edge="1" parent="1" source="28" target="27"><mxGeometry relative="1" as="geometry"/></mxCell><mxCell id="31" value="*" style="text;spacingTop=-5;" vertex="1" parent="1"><mxGeometry x="530" y="370" width="30" height="20" as="geometry"/></mxCell><mxCell id="32" value="*" style="text;spacingTop=-5;" vertex="1" parent="1"><mxGeometry x="530" y="480" width="30" height="20" as="geometry"/></mxCell><mxCell id="33" value="Υπηρεσία" style="whiteSpace=wrap" vertex="1" parent="1"><mxGeometry x="460" y="60" width="120" height="40" as="geometry"/></mxCell><mxCell id="34" value="Παρέχει" style="rhombus;whiteSpace=wrap" vertex="1" parent="1"><mxGeometry x="480" y="160" width="80" height="80" as="geometry"/></mxCell><mxCell id="35" value="" style="endArrow=none" edge="1" parent="1" source="34" target="33"><mxGeometry relative="1" as="geometry"/></mxCell><mxCell id="36" value="" style="endArrow=none" edge="1" parent="1" source="34" target="17"><mxGeometry relative="1" as="geometry"/></mxCell><mxCell id="37" value="*" style="text;spacingTop=-5;" vertex="1" parent="1"><mxGeometry x="530" y="290" width="30" height="20" as="geometry"/></mxCell><mxCell id="38" value="*" style="text;spacingTop=-5;" vertex="1" parent="1"><mxGeometry x="530" y="110" width="30" height="20" as="geometry"/></mxCell><mxCell id="39" value="Διαχειριστής" style="whiteSpace=wrap" vertex="1" parent="1"><mxGeometry x="155" y="570" width="120" height="40" as="geometry"/></mxCell></root></mxGraphModel>
|
|
|
@ -1 +0,0 @@
|
||||||
<mxGraphModel dx="800" dy="800" grid="1" guides="1" tooltips="1" connect="1" fold="1" page="1" pageScale="1" pageWidth="826" pageHeight="1169" style="default-style2"><root><mxCell id="0"/><mxCell id="1" parent="0"/><mxCell id="2" value=":Sync Library" style="shape=umlLifeline;perimeter=lifelinePerimeter;" parent="1" vertex="1"><mxGeometry x="30" y="30" width="100" height="580" as="geometry"/></mxCell><mxCell id="3" value=":Google API
Library" style="shape=umlLifeline;perimeter=lifelinePerimeter;" parent="1" vertex="1"><mxGeometry x="210" y="30" width="100" height="580" as="geometry"/></mxCell><mxCell id="4" value=":Google Calendar
Service" style="shape=umlLifeline;perimeter=lifelinePerimeter;" parent="1" vertex="1"><mxGeometry x="380" y="30" width="110" height="580" as="geometry"/></mxCell><mxCell id="7" value="" style="whiteSpace=wrap" parent="1" vertex="1"><mxGeometry x="70" y="85" width="20" height="485" as="geometry"/></mxCell><mxCell id="8" value="" parent="1" vertex="1"><mxGeometry x="250" y="262" width="20" height="258" as="geometry"/></mxCell><mxCell id="9" value="add_event" style="edgeStyle=elbowEdgeStyle;elbow=vertical;verticalAlign=bottom;endArrow=block;" parent="1" edge="1"><mxGeometry x="130" y="237" as="geometry"><mxPoint x="90" y="272" as="sourcePoint"/><mxPoint x="250" y="272" as="targetPoint"/></mxGeometry></mxCell><mxCell id="10" value="" parent="1" vertex="1"><mxGeometry x="426" y="310" width="20" height="173" as="geometry"/></mxCell><mxCell id="11" value="add_event" style="edgeStyle=elbowEdgeStyle;elbow=vertical;verticalAlign=bottom;endArrow=block;exitX=1;exitY=0.5" parent="1" edge="1"><mxGeometry x="326" y="277.5" as="geometry"><mxPoint x="270" y="327.5" as="sourcePoint"/><mxPoint x="426" y="327.5" as="targetPoint"/></mxGeometry></mxCell><mxCell id="12" value="return" style="edgeStyle=elbowEdgeStyle;elbow=vertical;verticalAlign=bottom;dashed=1;endArrow=open;endSize=8;" parent="1" edge="1"><mxGeometry x="326" y="432.5" as="geometry"><mxPoint x="270" y="467.5" as="targetPoint"/><mxPoint x="426" y="467.5" as="sourcePoint"/></mxGeometry></mxCell><mxCell id="13" value="invoke" style="edgeStyle=elbowEdgeStyle;elbow=vertical;align=left;endArrow=open;" parent="1" source="10" target="10" edge="1"><mxGeometry x="326" y="174.5" as="geometry"/></mxCell><mxCell id="17" value="return" style="edgeStyle=elbowEdgeStyle;elbow=vertical;verticalAlign=bottom;endArrow=none;startArrow=classic;startFill=1;endFill=0;dashed=1" parent="1" edge="1"><mxGeometry x="130" y="464" as="geometry"><mxPoint x="90" y="499" as="sourcePoint"/><mxPoint x="250" y="499" as="targetPoint"/></mxGeometry></mxCell><mxCell id="18" value="" parent="1" vertex="1"><mxGeometry x="250" y="110" width="20" height="130" as="geometry"/></mxCell><mxCell id="19" value="authenticate" style="edgeStyle=elbowEdgeStyle;elbow=vertical;verticalAlign=bottom;endArrow=block;" parent="1" edge="1" source="7"><mxGeometry x="150" y="86" as="geometry"><mxPoint x="100" y="120" as="sourcePoint"/><mxPoint x="250" y="121" as="targetPoint"/></mxGeometry></mxCell><mxCell id="20" value="" parent="1" vertex="1"><mxGeometry x="425" y="149.5" width="20" height="70" as="geometry"/></mxCell><mxCell id="21" value="authenticate" style="edgeStyle=elbowEdgeStyle;elbow=vertical;verticalAlign=bottom;endArrow=block;" parent="1" target="20" edge="1"><mxGeometry x="340" y="125.5" as="geometry"><mxPoint x="270" y="160.5" as="sourcePoint"/><mxPoint x="420" y="160" as="targetPoint"/></mxGeometry></mxCell><mxCell id="22" value="return" style="edgeStyle=elbowEdgeStyle;elbow=vertical;verticalAlign=bottom;dashed=1;endArrow=open;endSize=8;" parent="1" edge="1"><mxGeometry x="340" y="174.5" as="geometry"><mxPoint x="270" y="209.5" as="targetPoint"/><mxPoint x="420" y="210" as="sourcePoint"/></mxGeometry></mxCell><mxCell id="23" value="invoke" style="edgeStyle=elbowEdgeStyle;elbow=vertical;align=left;endArrow=open;" parent="1" source="20" target="20" edge="1"><mxGeometry x="330" y="149.5" as="geometry"/></mxCell><mxCell id="24" value="return" style="edgeStyle=elbowEdgeStyle;elbow=vertical;verticalAlign=bottom;endArrow=none;endFill=0;startArrow=classic;startFill=1;dashed=1" edge="1" parent="1" source="7"><mxGeometry x="151" y="194" as="geometry"><mxPoint x="100" y="230" as="sourcePoint"/><mxPoint x="251" y="229" as="targetPoint"/></mxGeometry></mxCell></root></mxGraphModel>
|
|
|
@ -1 +0,0 @@
|
||||||
<mxGraphModel dx="800" dy="800" grid="1" guides="1" tooltips="1" connect="1" fold="1" page="1" pageScale="1" pageWidth="826" pageHeight="1169" style="default-style2"><root><mxCell id="0"/><mxCell id="1" parent="0"/><mxCell id="2" value="PHP" style="swimlane;whiteSpace=wrap" vertex="1" parent="1"><mxGeometry x="20" y="20" width="380" height="230" as="geometry"/></mxCell><mxCell id="3" value="CodeIgniter
 (MVC Framework)" style="whiteSpace=wrap" vertex="1" parent="2"><mxGeometry x="20" y="37" width="340" height="55" as="geometry"/></mxCell><mxCell id="4" value="Models" style="whiteSpace=wrap" vertex="1" parent="2"><mxGeometry x="20" y="102" width="100" height="45" as="geometry"/></mxCell><mxCell id="5" value="Views" style="whiteSpace=wrap" vertex="1" parent="2"><mxGeometry x="140" y="102" width="100" height="45" as="geometry"/></mxCell><mxCell id="6" value="Controllers" style="whiteSpace=wrap" vertex="1" parent="2"><mxGeometry x="260" y="102" width="100" height="45" as="geometry"/></mxCell><mxCell id="20" value="Google API Library" style="whiteSpace=wrap" vertex="1" parent="2"><mxGeometry x="20" y="158" width="340" height="55" as="geometry"/></mxCell><mxCell id="8" value="JavaScript" style="swimlane;whiteSpace=wrap" vertex="1" parent="1"><mxGeometry x="20" y="260.25" width="380" height="232.5" as="geometry"/></mxCell><mxCell id="9" value="jQuery & jQuery UI" style="whiteSpace=wrap" vertex="1" parent="8"><mxGeometry x="20" y="34" width="340" height="55" as="geometry"/></mxCell><mxCell id="13" value="Bootstrap Javascript" style="whiteSpace=wrap" vertex="1" parent="8"><mxGeometry x="20" y="99" width="340" height="55" as="geometry"/></mxCell><mxCell id="10" value="Namespaces" style="whiteSpace=wrap" vertex="1" parent="8"><mxGeometry x="20" y="166" width="160" height="45" as="geometry"/></mxCell><mxCell id="11" value="Classes" style="whiteSpace=wrap" vertex="1" parent="8"><mxGeometry x="200" y="166" width="160" height="45" as="geometry"/></mxCell><mxCell id="14" value="CSS" style="swimlane;whiteSpace=wrap" vertex="1" parent="1"><mxGeometry x="20" y="512.5" width="380" height="247.5" as="geometry"/></mxCell><mxCell id="15" value="Boostrap" style="whiteSpace=wrap" vertex="1" parent="14"><mxGeometry x="20" y="36" width="340" height="55" as="geometry"/></mxCell><mxCell id="16" value="Frontend CSS" style="whiteSpace=wrap" vertex="1" parent="14"><mxGeometry x="20" y="104" width="340" height="55" as="geometry"/></mxCell><mxCell id="19" value="Backend CSS" style="whiteSpace=wrap" vertex="1" parent="14"><mxGeometry x="20" y="172" width="340" height="55" as="geometry"/></mxCell></root></mxGraphModel>
|
|
Before Width: | Height: | Size: 49 KiB |
Before Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 366 KiB |
Before Width: | Height: | Size: 177 KiB |
Before Width: | Height: | Size: 284 KiB |
Before Width: | Height: | Size: 160 KiB |
Before Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 64 KiB |
Before Width: | Height: | Size: 94 KiB |
Before Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 49 KiB |
Before Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 23 KiB |
|
@ -1,45 +0,0 @@
|
||||||
\chapter{Συμπεράσματα}
|
|
||||||
Το αποτέλεσμα της εκπόνησης της εργασίας είναι ένα πλήρης σύστημα διαχείρισης ραντεβού το οποίο μπορεί να διαμορφωθεί επαρκώς έτσι ώστε να καλύψει τις ανάγκες οποιασδήποτε επιχείρισης ανεξαρτήτου ειδικότητας και μεγέθους. Ο αρχικός σχεδιασμός αποδείχθηκε σωστός και έτσι το τελικό προϊόν λογισμικού πληροί τις απαιτήσεις για τις οποίες αναπτύχθηκε.
|
|
||||||
|
|
||||||
\section{Προβλήματα}
|
|
||||||
Σε αυτήν την ενότητα περιγράφονται τα σημαντικότερα προβλήματα που αντιμετωπίστηκαν κατά την διάρκεια της ανάπτυξης του Easy!Appointments. Επεξηγούνται οι αποφάσεις που πάρθηκαν στην κάθε περίπτωση και αναλύονται οι λύσεις που χρησιμοποιήθηκαν.
|
|
||||||
|
|
||||||
\subsection{Διαχείριση χρόνου}
|
|
||||||
Σημαντικότερο πρόβλημα σχετικά με την υλοποίηση της εφαρμογής ήταν η χρονική καθυστέρηση μιας και ανάμεσα στην ανάληψη της εργασίας και την περαίωση της, πραγματοποιήθηκε η πρακτική άσκηση σε εταιρεία πληροφορικής καθώς και εργασία εκτός σχολής με άλλες εταιρείες του ίδιου τομέα. Οι εξωτερικές υποχρεώσεις αυτές αποσπούσαν την συνεχή και ομαλή ανάπτυξη, κάτι που συνεχώς διασπούσε τον ειρμό και τον δημιουργικό οίστρο. Συμπέρασμα αυτού του σημαντικού προβλήματος είναι ότι θα πρέπει να γίνεται σαφής και ορθός προγραμματισμός του χρόνου υλοποίησης ενός έργου γιατί διαφορετικά οι πιθανότητες για χαμηλότερη ποιότητα υπηρεσίας ή ακόμα και αποτυχίας του έργου αυξάνονται εκθετικά. Σε αυτό μπορεί να συντελέσει και η πληθώρα των εφαρμογών οι οποίες αποσκοπούν στην αποδοτικότερη διαχείριση έργων λογισμικού οι οποίες είναι διαθέσιμες είτε δωρεάν, είτε έναντι αμοιβής.
|
|
||||||
|
|
||||||
\subsection{Συγχρονισμός δεδομένων με το Google Calendar}
|
|
||||||
Όσον αφορά την συνεργασία του συστήματος με την υπηρεσία Google Calendar αλλά και γενικότερα με άλλες πιθανές υπηρεσίες το ζήτημα παραμένει στο πως θα παραμείνουν τα δεδομένα ακέραια και ενημερωμένα και στα δύο συστήματα, όταν δεν υπάρχει ένα κοινό μέσο αποθήκευσης. Το θέμα γιγαντώνεται μάλιστα όταν δεν υπάρχει πρόσβαση στον κώδικα του ενός από τα δύο συστήματα έτσι ώστε να δημιουργηθεί μια "γέφυρα δεδομένων". Για την επίλυση αυτού του θέματος ήταν αναγκαίο να δημιουργηθεί ένας αλγόριθμος συγχρονισμού ο οποίος θα ενεργοποιούνταν από την πλευρά του Easy!Appointments και θα αναλάμβανε την ενημέρωση και τον δύο συστημάτων με τα τελευταία δεδομένα. Για αυτόν τον σκοπό θα έπρεπε να καταγραφούν και να υλοποιηθούν κάποιοι κανόνες συγχρονισμού οι οποίοι θα μετέφεραν επιτυχώς τα ραντεβού αμφίδρομα και στα δύο συστήματα. Στις περιπτώσεις όπου η μεταφορά αυτή θα ήταν αδύνατη (σύγκρουση δεδομένων) ο χρήστης θα έπρεπε να αποφασίσει ποια εκδοχή των δεδομένων θα υπερισχύσει στο τέλος.
|
|
||||||
|
|
||||||
\subsection{Διαχωρισμός δικαιωμάτων χρηστών}
|
|
||||||
Ένα ακόμα πρόβλημα που αντιμετωπίστηκε κατά την διάρκεια την ανάπτυξης του έργου ήταν ο διαχωρισμός των δικαιωμάτων των χρηστών μέσα στο σύστημα. Ο κάθε χρήστης αναλόγως το είδος του (διαχειριστής, πάροχος, γραμματέας) έχει διαφορετικές δυνατότητες και δικαιώματα στα δεδομένα που αποθηκεύονται από το σύστημα. Αυτό συμβαίνει γιατί στις περισσότερες περιπτώσεις θα πρέπει να τηρηθεί η ιεραρχία της επιχείρησης αλλά και επίσης γιατί θα πρέπει να διασφαλιστεί η ακεραιότητα των δεδομένων από τυχόν εσφαλμένες ενέργειες χρηστών σε βασικές ρυθμίσεις του συστήματος. Για τις κυριότερες ρυθμίσεις απαιτούνται τα δικαιώματα διαχειριστή και έτσι το σύστημα χρειάζεται απαραιτήτως πάντα έναν χρήστη διαχειριστή (ο χρήστης που δημιουργείται κατά την εγκατάσταση είναι ουσιαστικά ο πρώτος διαχειριστής της εφαρμογής). Για να λυθεί αυτό το πρόβλημα η εγγραφή του κάθε χρήστη στην βάση δεδομένων συνδέεται με έναν ρόλο ο οποίος περιέχει τα δικαιώματα που του αντιστοιχούν. Έτσι για παράδειγμα ένας χρήστης που προορίζεται για πάροχος υπηρεσίας, θα έχει τα δικαιώματα που αντιστοιχούν στον ρόλο "Πάροχος Υπηρεσίας" όπως αυτά είναι αποθηκευμένα στην βάση δεδομένων. Έτσι κάθε φορά που συνδέεται ένας χρήστης στο διαχειριστικό κομμάτι της εφαρμογής τα δεδομένα σχετικά με τα δικαιώματα του και τον ρόλο του διαβάζονται από σελίδα σε σελίδα και η εφαρμογή μπορεί και γνωρίζει με ποιόν τρόπο θα πρέπει να εμφανιστούν τα δεδομένα και ποιες ενέργειες είναι διαθέσιμες στην κάθε περίπτωση.
|
|
||||||
|
|
||||||
\section{Εξέλιξη της εφαρμογής}
|
|
||||||
Όπως και σε κάθε έργο λογισμικού, υπάρχουν πολλά πράγματα τα οποία μπορούν να εξελιχθούν και να βελτιωθούν καθώς και δυνατότητες οι οποίες μπορούν να προστεθούν για να κάνουν την εφαρμογή πιο εύχρηστη και αποδοτικότερη. Οι βελτιώσεις αυτές γίνονται στην φάση της συντήρησης και επέκτασης σταδιακά, με σκοπό την ύπαρξη ενός ενημερωμένου προϊόντος στην αγορά. Με αυτόν τον τρόπο οι εταιρείες θα μπορούν να εμπιστεύονται την εν λόγω εφαρμογή και να την χρησιμοποιούν ως το δικό τους εργαλείο διαχείρισης των ραντεβού. Παρακάτω περιγράφονται κάποια σημεία στα οποία θα μπορούσε να εξελιχθεί μελλοντικά το σύστημα που παράχθηκε.
|
|
||||||
|
|
||||||
\subsection{Mobile design}
|
|
||||||
Με την πάροδο του χρόνου όλο και περισσότερες "έξυπνες" συσκευές βρίσκονται στα χέρια των καταναλωτών και έτσι δημιουργείται η ανάγκη για χρήση των διαδικτυακών εφαρμογών από οθόνες που έχουν διαφορετικά μεγέθη οθονών. Εφόσον η σχεδίαση για όλες τις διαστάσεις οθονών υπολογιστή έχουν καλυφθεί, το επόμενο βήμα είναι να σχεδιαστεί το σύστημα για κινητές συσκευές και tablet. Με αυτόν τον τρόπο θα μπορούν οι χρήστες του Easy!Appointments να χρησιμοποιούν το σύστημα από το κινητό τους πολύ πιο άνετα και έτσι να είναι πάντα ενημερωμένοι σχετικά με τα ραντεβού τους όπου και αν βρίσκονται. Προϋπόθεση για αυτό πάντα είναι μια ενεργή σύνδεση με το διαδίκτυο. Για να υλοποιηθεί αυτή η δυνατότητα θα χρειαστεί να γραφεί CSS κώδικας ο οποίος να εμφανίζει την εφαρμογή διαφορετικά σε κινητές συσκευές.
|
|
||||||
|
|
||||||
\subsection{Μετάφραση της διεπαφής χρήστη}
|
|
||||||
Η πρώτη υλοποίηση του συστήματος έχει γίνει εξολοκλήρου στην αγγλική γλώσσα όπως και με τα περισσότερα συστήματα που απευθύνονται σε ένα ευρύ καταναλωτικό κοινό. Το Easy!Appointments δέχεται κείμενο και σε άλλες γλώσσες (χρησιμοποιείται το encoding UTF-8) αλλά η διεπαφή, τα μηνύματα και τα αντικείμενα ελέγχου είναι όλα στα Αγγλικά. Για να γίνει πιο εύκολη η χρήση της εφαρμογής και από ανθρώπους οι οποίοι δεν είναι τόσο εξοικειωμένοι με αυτήν την γλώσσα θα πρέπει να μεταφραστεί όλο το σύστημα και σε άλλες κοινές γλώσσες. Για να επιτευχθεί αυτό στην συγκεκριμένη περίπτωση θα πρέπει να χρησιμοποιηθεί μια συγκεκριμένη τεχνική, όπως ενδεικνύεται από τον ιστότοπο του κατασκευαστή του CodeIgniter.
|
|
||||||
|
|
||||||
\subsection{Αναφορές δεδομένων}
|
|
||||||
Το σύστημα μέσω της λειτουργίας του κρατάει διάφορα δεδομένα (ραντεβού, πελάτες, πάροχοι κτλ). Καλό θα ήταν αυτά τα δεδομένα να μπορούν να εξαχθούν με κάποιον τρόπο έτσι ώστε να μπορέσουν να χρησιμοποιηθούν και με άλλους τρόπους. Μια περίπτωση χρήσης θα ήταν η εξαγωγή των σημερινών ραντεβού ενός πάροχου σε μια εκτυπώσιμη αναφορά έτσι ώστε να μπορεί ο χρήστης να την τυπώσει και να την έχει ως λίστα στο γραφείο. Μια άλλη περίπτωση χρήσης θα ήταν να εκτυπωθούν τα στοιχεία ενός πελάτη καθώς και το ιστορικό των ραντεβού του. Οι αναφορές αυτές είναι πολύ χρήσιμες γιατί μπορούν να αναδείξουν γρήγορα δεδομένα και μάλιστα σε εκτυπώσιμη μορφή, κάτι που χρειάζονται ακόμα πολλές εταιρείες.
|
|
||||||
|
|
||||||
\subsection{Στατιστικές πληροφορίες}
|
|
||||||
Μια χρήσιμη μελλοντική δυνατότητα θα ήταν η συλλογή στατιστικών πληροφοριών σχετικά με τα ραντεβού που κλίνονται στο σύστημα. Από αυτήν την διαδικασία θα μπορούσαν να βγουν σημαντικές πληροφορίες όπως το ποια υπηρεσία ή πάροχος προτιμάται πιο συχνά, ποιες μέρες έχουν τα περισσότερα ραντεβού, πόσο συχνά ακυρώνονται τα ραντεβού και σε πόσο χρονικό διάστημα πριν. Αυτές οι πληροφορίες είναι πολύ σημαντικές για μια εταιρεία η οποία λειτουργεί με κρατήσεις ραντεβού γιατί έτσι μπορεί να γνωρίζει με ποιόν τρόπο λειτουργεί το πελατειακό κοινό της και έτσι να λειτουργεί αναλόγως για να παρέχει καλύτερη εξυπηρέτηση. Ένα παράδειγμα θα ήταν η περίπτωση ενός μεγάλου κομμωτηρίου στην οποία οι πελάτες θα κρατούσαν πάρα πολλά ραντεβού το Σάββατο κάθε εβδομάδας, γιατί πιθανόν έχουν περισσότερο χρόνο. Τα στατιστικά (εκτός της πείρας) θα έδειχναν την αυξημένη κίνηση του Σαββάτου και έτσι ο διαχειριστής θα είχε διαθέσιμους όλους του πάροχους προς ραντεβού, για να μπορέσει να καλυφθεί το κοινό όσο καλύτερα γίνεται.
|
|
||||||
|
|
||||||
\subsection{Δημιουργία RESTful υπηρεσίας}
|
|
||||||
Κάθε μεγάλο διαδικτυακό σύστημα παρέχει και μια RESTful υπηρεσία η οποία μπορεί να απαντάει με δεδομένα σε διάφορες κλήσεις που της γίνονται, εφόσον βέβαια έχει πιστοποιηθεί ο client που επικοινωνεί μαζί τους. Με αυτόν τον τρόπο θα μπορούν άλλοι προγραμματιστές να φτιάχνουν εφαρμογές οι οποίες θα επικοινωνούν με το Easy!Appointments και θα διαχειρίζονται τα δεδομένα του συστήματος. Η υλοποίηση αυτής της δυνατότητας θα βοηθούσε πολύ την εξέλιξη και την χρήση του Easy!Appointments γιατί από εδώ και πέρα διάφορες εφαρμογές θα υλοποιούνταν κάνοντας δυνατή την χρήση των δεδομένων σε πολλές διαφορετικές περιστάσεις. Κάτι που είναι πάρα πολύ χρήσιμο για κάθε επαγγελματία (παραδείγματος χάρη η χρήση πελατών από CRM εφαρμογή).
|
|
||||||
|
|
||||||
\subsection{Βελτίωση κώδικα}
|
|
||||||
Τελευταίο αλλά και όχι λιγότερο σημαντικό είναι η συνεχής βελτίωση και ενημέρωση του κώδικα έτσι ώστε να είναι πάντα στην καλύτερη δυνατή κατάσταση. Καθώς εξελίσσεται ένα σύστημα λογισμικού είναι απαραίτητο να βελτιώνεται ο κώδικας και η δομή του. Επίσης είναι απαραίτητο να ενημερώνονται και τα εξωτερικά εργαλεία τα οποία χρησιμοποιούνται έτσι ώστε να διασφαλίζεται η ασφάλεια και η ποιότητα του συστήματος. Κατά καιρούς εμφανίζονται διάφορες ενημερώσεις ασφαλείας αλλά και διορθώσεων σφαλμάτων σε αυτά τα framework (CodeIgniter, jQuery κτλ) τα οποία θα χρειαστεί να συμπεριληφθούν και στο Easy!Appointments. Κάθε φορά που ο χρήστης λαμβάνει μια νέα έκδοση της εφαρμογής θα πρέπει ο κώδικας που την απαρτίζει να βρίσκεται σε πολύ καλή κατάσταση, να έχει ελεγχθεί και να λειτουργεί σωστά έτσι ώστε να εμπνέει εμπιστοσύνη προς τους χρήστες.
|
|
||||||
|
|
||||||
\section{Πληροφορίες}
|
|
||||||
Η διαχείριση του έργου έγινε στην υπηρεσία Google Code και ο κώδικας είναι διαθέσιμος στην διεύθυνση \url{https://code.google.com/p/easy-appointments/}. Υπάρχει επίσης και η επίσημη ιστοσελίδα του Easy!Appointments στην διεύθυνση \url{http://easyappointments.org}.
|
|
||||||
\newline
|
|
||||||
\begin{figure}[H]
|
|
||||||
\centering
|
|
||||||
\includegraphics[width=150mm]{images/gantt-simple.jpg}
|
|
||||||
\caption{Χρονοδιάγραμμα Υλοποίησης (Gantt)}
|
|
||||||
\label{gantt-simple}
|
|
||||||
\end{figure}
|
|
|
@ -1,40 +0,0 @@
|
||||||
%% ΕΞΩΤΕΡΙΚΑ ΕΡΓΑΛΕΙΑ
|
|
||||||
%% Σε αυτό το κεφάλαιο γίνεται περιγραφή των υπόλοιπων εξωτερικών
|
|
||||||
%% εργαλείων που χρησιμοποιήθηκαν από για την υλοποίηση του συστήματος
|
|
||||||
%% κρατήσεων ραντεβού.
|
|
||||||
|
|
||||||
\chapter{Εξωτερικά Εργαλεία}
|
|
||||||
Εκτός του Calendar API και των βιβλιοθηκών που παρέχει η Google, έχουν χρησιμοποιηθεί και κάποια άλλα εργαλεία ανάπτυξης λογισμικού τα οποία βοήθησαν στην άρτια και ποιοτικότερη παραγωγή του συστήματος κρατήσεων ραντεβού. Τα εργαλεία αυτά είναι όλα ανοιχτού κώδικα (open source) και έχουν στόχο να βοηθήσουν τον προγραμματιστή να επικεντρωθεί περισσότερο σε αυτό που έχει να κάνει και όχι τόσο στα τετριμμένα πράγματα τα οποία αποσπούν μεγάλο χρονικό διάστημα άσκοπα. Εν ολίγοις πρόκειται για ένα σύνολο από διάφορα framework τα οποία είναι πολύ χρήσιμα για οποιαδήποτε ανάπτυξη λογισμικού.
|
|
||||||
|
|
||||||
\section{CodeIgniter}
|
|
||||||
Το CodeIgniter είναι ένα PHP framework το οποίο έχει ως στόχο την αποδοτικότητα και την ταχύτητα μιας και καταναλώνει πολύ λίγους υπολογιστικούς πόρους σε αντίθεση με άλλα βοηθητικά συστήματα του είδους του. Θετικό στοιχείο είναι ότι είναι πολύ απλό στην χρήση, δίνει την δυνατότητα στον προγραμματιστή να διαμορφώσει τον πυρήνα του καταπώς τον βολεύει και βασίζεται στην αρχιτεκτονική MVC (Model - View - Controller). Όντας έργο ανοιχτού λογισμικού κατέχει μια μεγάλη κοινότητα που το υποστηρίζει και επίσης προσφέρει μια καλά ενημερωμένη γνωσιακή βάση, η οποία μπορεί να καθοδηγήσει τον προγραμματιστή στο πως θα χρησιμοποιήσει το framework.
|
|
||||||
|
|
||||||
Η αρχιτεκτονική MVC είναι η πλέον διαδεδομένη κυρίως στις διαδικτυακές εφαρμογές αφού αποσκοπεί στην καλύτερη οργάνωση και συντήρηση του κώδικα. Ουσιαστικά πρόκειται για τον διαχωρισμό της εφαρμογής σε τρία μέρη:
|
|
||||||
\begin{enumerate}
|
|
||||||
\item Models: Περιέχουν συναρτήσεις και μεθόδους που αλληλεπιδρούν με την βάση δεδομένων. Χρησιμοποιούνται σε διάφορες περιπτώσεις από τους Controllers. Με αυτόν τον τρόπο επιτυγχάνεται η επαναχρησιμοποίηση ενός μέρους του κώδικα, κάτι το οποίο είναι πολύ σημαντικό στην αρχιτεκτονική ενός συστήματος.
|
|
||||||
\item Views: Τα views είναι τα κομμάτια κώδικα τα οποία παράγουν το αποτέλεσμα το οποίο βλέπει ο χρήστης κάθε φορά. Στόχος τους είναι απλώς να δείξουν και όχι να υπολογίσουν ή να φέρουν κάποια δεδομένα (αυτό είναι δουλειά των άλλων δυο τμημάτων της αρχιτεκτονικής). Κάθε φορά που χρειάζεται να αλλάξει κάτι στην εμφάνιση του συστήματος μπορεί να γίνει αλλαγή στο αντίστοιχο view χωρίς να επηρεαστούν τα άλλα συστήματα.
|
|
||||||
\item Controllers: Το μέρος αυτό του συστήματος αναλαμβάνει να οργανώσει τα άλλα δυο. Κάθε φορά που πρέπει να παραχθεί μια σελίδα η διαδικασία θα ξεκινήσει από τον αντίστοιχο controller. Αυτός στην συνέχεια θα καλέσει τις απαραίτητες συναρτήσεις και θα παρέχει τα δεδομένα που απαιτεί το view για να εμφανιστεί σωστά η σελίδα.
|
|
||||||
\end{enumerate}
|
|
||||||
|
|
||||||
\begin{figure}
|
|
||||||
\centering
|
|
||||||
\includegraphics[width=70mm]{images/mvc.png}
|
|
||||||
\caption{Αρχιτεκτονική MVC}
|
|
||||||
\label{mvc}
|
|
||||||
\end{figure}
|
|
||||||
|
|
||||||
Το σύστημα που υλοποιήθηκε χρησιμοποιεί το CodeIgniter για την κάλυψη των βασικών εργασιών έτσι ώστε να υπάρχει η δομή MVC στον κώδικα. Επίσης γίνεται χρήση της ενσωματωμένης βιβλιοθήκης επικοινωνίας με την βάση δεδομένων. Εκτός αυτών των δύο, ο υπόλοιπος κώδικας έχει γραφεί κανονικά και τηρεί τις προϋποθέσεις της πτυχιακής εργασίας.
|
|
||||||
|
|
||||||
\section {jQuery \& jQuery UI}
|
|
||||||
Ένα μεγάλο μέρος των σύγχρονων διαδικτυακών εφαρμογών βασίζει την λειτουργία του σε κώδικα JavaScript έτσι ώστε να κάνει το λογισμικό πιο φιλικό προς τον χρήστη. Διάφορες βιβλιοθήκες έχουν δημιουργηθεί τα τελευταία χρόνια που στόχο έχουν την εξέλιξη και την αποδοτικότερη χρήση της γλώσσας JavaScript. Η πιο δημοφιλής από όλες αυτές τις βιβλιοθήκες είναι η jQuery η οποία συνοδεύεται από το jQuery UI, ένα framework για την παραγωγή στοιχείων ελέγχου (controls) στα οποία μπορεί ο κάθε χρήστης να εκτελέσει διάφορες ενέργειες. Το jQuery έχει καταφέρει να απλοποιήσει την συγγραφή JavaScript κώδικα και επιπλέον παρέχει στην διάθεση του προγραμματιστή έτοιμες ρουτίνες animation και διαφόρων άλλων ενεργειών, οι οποίες διαφορετικά θα καταλάμβαναν αρκετό χρόνο για την υλοποίηση τους. Πρόκειται για μια βιβλιοθήκη ανοιχτού λογισμικού η οποία υποστηρίζεται από μια πολύ μεγάλη κοινότητα προγραμματιστών. Υπάρχει επίσης πληθώρα πρόσθετων (plugins) με λειτουργίες οι οποίες δεν είναι διαθέσιμες στην βασική βιβλιοθήκη.
|
|
||||||
|
|
||||||
Η jQuery ουσιαστικά λειτουργεί σαν ένα επίπεδο πάνω από την JavaScript βοηθώντας τον προγραμματιστή να γράψει διάφορες δομές κώδικα πιο γρήγορα και οργανωμένα. Ο κώδικας που γράφεται είναι πάλι JavaScript οπότε είναι πολύ εύκολο στον καθένα να χρησιμοποιήσει την βιβλιοθήκη. Στόχος της είναι η πιο εύκολη περιήγηση στα αντικείμενα μιας σελίδας (DOM elements), η εύκολη δημιουργία εφέ κινήσεων τα οποία προσδίδουν πολύ αισθητικά σε μια ιστοσελίδα, η ευκολότερη χρήση της τεχνολογίας AJAX, μιας τεχνολογίας η οποία χρησιμοποιείται όλο και περισσότερο από τα σύγχρονα συστήματα.
|
|
||||||
|
|
||||||
Το σύστημα που παράχθηκε χρησιμοποιεί αυτήν την βιβλιοθήκη για τον προγραμματισμό του client-side μέρους της εφαρμογής. Ανάλογα με την κάθε περίσταση, μερικές φορές είναι αποδοτικότερο και χρησιμότερο να χρησιμοποιηθεί JavaScript έναντι της PHP και για αυτόν τον λόγο επιλέχθηκε το jQuery Framework ως εργαλείο κατά την υλοποίηση του συστήματος.
|
|
||||||
|
|
||||||
\section {Bootstrap}
|
|
||||||
Το Bootstrap είναι ένα ολοκληρωμένο CSS Framework με την προσθήκη κάποιων βιβλιοθηκών JavaScript έτσι ώστε να προσφέρει μερικές επιπλέον δυνατότητες. Έχει κατασκευαστεί από την εταιρεία πίσω από την σελίδα κοινωνικής δικτύωσης Twitter και χρησιμοποιείται από αυτήν ως βάση για την υλοποίηση της. Η εταιρεία έχει διαθέσει το framework ως ανοιχτό λογισμικό και οι προγραμματιστές μπορούν να το χρησιμοποιήσουν ελεύθερα στις σελίδες τους. Η ίδια η εταιρεία επωφελείται μέσω της συμμετοχής της κοινότητας για να αναπτύξει περαιτέρω το framework.
|
|
||||||
|
|
||||||
Το Bootstrap περιέχει έτοιμο κώδικα CSS ο οποίος ακολουθεί την μεθοδολογία παραγωγής responsive ιστοσελίδων. Με την έννοια αυτή εννοείται ότι η μορφοποίηση των σελίδων στοχεύει στο να είναι συμβατή με οποιαδήποτε συσκευή, λειτουργικό σύστημα και περιηγητή ιστού. Είναι πολύ σημαντικό για την αναγνωρισιμότητα και ευχρηστία μιας εφαρμογής το να είναι διαθέσιμη σε οποιοδήποτε μηχάνημα υποστηρίζει τα τελευταία standards του ιστού. Το JavaScript μέρος του framework χρησιμοποιεί το jQuery για την υλοποίηση διαφόρων τεχνικών (πχ εμφάνιση παραθύρου διαλόγου).
|
|
||||||
|
|
||||||
Στην παραγωγή του συστήματος κρατήσεων ραντεβού χρησιμοποιήθηκε ως η βάση για τη μορφοποίηση και κάποιες μέθοδοι JavaScript φάνηκαν αρκετά χρήσιμα σε κάποια σημεία. Στην συνέχεια με βάση αυτά γράφτηκαν ξεχωριστά αρχεία CSS και JavaScript τα οποία αποτελούν το τελικό αποτέλεσμα που έπρεπε να επιτευχθεί.
|
|
|
@ -1,153 +0,0 @@
|
||||||
%% ΠΕΡΙΓΡΑΦΗ ΤΟΥ GOOGLE CALENDAR API
|
|
||||||
%% Σε αυτό το κεφάλαιο περιγράφεται το Google Calendar API
|
|
||||||
%% και το πως χρησιμοποιείται από το σύστημα για να πραγματοποιηθεί
|
|
||||||
%% η διαδικασία του συγχρονισμού.
|
|
||||||
|
|
||||||
\chapter{Google Calendar API}
|
|
||||||
Το Ημερολόγιο της Google είναι μια διαδικτυακή εφαρμογή που επιτρέπει στους χρήστες της να αποθηκεύουν και να διαχειρίζονται τα ραντεβού και τα συμβάντα τους σε ένα όμορφο περιβάλλον. Εκτός αυτού, υπάρχουν πολλές πρόσθετες δυνατότητες όπως ο συγχρονισμός ημερολογίου με κάποια άλλη εφαρμογή ή η κοινή χρήση ενός ημερολογίου από
|
|
||||||
πολλά άτομα.
|
|
||||||
|
|
||||||
Όπως και με τα περισσότερα προϊόντα της Google παρέχονται εργαλεία με τα οποία μπορούν οι προγραμματιστές να επικοινωνήσουν και να λάβουν δεδομένα από τις υπηρεσίες της εταιρείας. Με
|
|
||||||
αυτόν τον τρόπο είναι δυνατή η ανάπτυξη εφαρμογών οι οποίες διαχειρίζονται αυτά τα δεδομένα, διευκολύνοντας έτσι τον χρήστη.
|
|
||||||
|
|
||||||
\begin{figure}[h]
|
|
||||||
\centering
|
|
||||||
\includegraphics[width=150mm]{images/google-calendar-api.png}
|
|
||||||
\caption{Ιστότοπος περιγραφής του Google Calendar API.}
|
|
||||||
\label{google-calendar-api}
|
|
||||||
\end{figure}
|
|
||||||
|
|
||||||
Το Google Calendar API (Application Programming Interface)
|
|
||||||
είναι μια πλατφόρμα διαχείρισης συμβάντων ενός ημερολογίου από την Google. Επιτρέπει στον προγραμματιστή να πραγματοποιήσει λειτουργίες προσθήκης, επεξεργασίας, διαγραφής και αναζήτησης συμβάντων μέσω ενός RESTful στυλ κλήσεων προς τον server.
|
|
||||||
|
|
||||||
Με την έννοια RESTful (Representional State Transfer) εννοείται ένας από τους πιο δημοφιλής τρόπους επικοινωνίας στον παγκόσμιο ιστό. Η επικοινωνία γίνεται με την χρήση ειδικών αιτήσεων προς τους servers οι οποίοι με την σειρά τους είναι σε θέση να τις επεξεργαστούν και να επιστρέψουν δεδομένα πίσω στους clients. Οι μέθοδοι αιτήσεων που είναι διαθέσιμες είναι:
|
|
||||||
\begin{enumerate}
|
|
||||||
\item GET
|
|
||||||
\item POST
|
|
||||||
\item PUT
|
|
||||||
\item DELETE
|
|
||||||
\end{enumerate}
|
|
||||||
|
|
||||||
Πρακτικά η μέθοδος επικοινωνίας RESTFul μπορεί να χρησιμοποιηθεί από οποιοδήποτε σύστημα υποστηρίζει το πρωτόκολλο HTTP. Για να διευκολύνει όμως η Google τους προγραμματιστές έχει αναπτύξει βιβλιοθήκες κώδικα σε διάφορες γλώσσες προγραμματισμού (PHP, Java, .NET, Ruby κτλ) οι οποίες περιέχουν έτοιμες μεθόδους επικοινωνίας με τις υπηρεσίες της. Έτσι διευκολύνεται πολύ η διαδικασία ανάπτυξης μιας εφαρμογής που βασίζεται πάνω στα δεδομένα των χρηστών της Google.
|
|
||||||
|
|
||||||
Για να αποτραπεί η υπερβολική χρήση της υπηρεσίας Calendar, η εταιρεία έχει θέσει ένα υπέρτατο όριο 10.000 request την ημέρα. Αν κάποια εταιρεία ξεπεράσει αυτό το όριο τότε θα χρειαστεί να πληρώσει κάποιο αντίτιμο για να μπορέσει να συνεχίσει κανονικά την χρήση. Για αυτό τον λόγο είναι και απαραίτητο οποιοσδήποτε client χρησιμοποιεί το Calendar API, να έχει πρώτα δημιουργήσει ένα API Key μέσω της σελίδας API Console που προσφέρει η Google.
|
|
||||||
|
|
||||||
\section {Περιγραφή του Calendar API}
|
|
||||||
Το Ημερολόγιο της Google είναι ένα πολύ δυνατό και ευέλικτο εργαλείο. Οι χρήστες μπορούν να βλέπουν το ίδιο ημερολόγιο σε οποιαδήποτε συσκευή βρίσκονται έχοντας απλώς σύνδεση με το διαδίκτυο (για να είναι εφικτή η λήψη των δεδομένων από την υπηρεσία). Όλες οι εφαρμογές αυτές χρησιμοποιούν το API για να υλοποιήσουν τις βασικές λειτουργίες ενός ημερολογίου, δηλαδή την διαχείριση και την εύκολη εύρεση συμβάντων που είναι καταχωρημένα στο Google Calendar. Αφού γίνουν οι αλλαγές αυτές θα χρειαστεί να εκτελεστεί η διαδικασία του συγχρονισμού έτσι ώστε τα νέα δεδομένα να είναι και στις υπόλοιπες εφαρμογές που έχουν πρόσβαση στο ημερολόγιο.
|
|
||||||
|
|
||||||
Στην ευρεία χρήση της υπηρεσίας συντελεί το ότι η πλατφόρμα του ημερολογίου είναι συμβατή με διάφορες γλώσσες προγραμματισμού και έτσι μπορούν να υλοποιηθούν εφαρμογές για όλες τις συσκευές με εξελιγμένο λειτουργικό σύστημα (Windows, Linux, Mac OS, Android, iOS, Windows Phone κτλ).
|
|
||||||
|
|
||||||
Οι βασικές έννοιες του συστήματος ενός ημερολογίου είναι:
|
|
||||||
|
|
||||||
\begin{itemize}
|
|
||||||
\item Συμβάν (Event) - αντιπροσωπεύει ένα συμβάν στο ημερολόγιο το οποίο έχει τίτλο, περιγραφή, ημερομηνία και συμμετέχοντες.
|
|
||||||
|
|
||||||
\item Ημερολόγιο (Calendar) - αντιπροσωπεύει ένα ημερολόγιο το οποίο περιέχει πολλά συμβάντα. Ένας χρήστης μπορεί να έχει πολλά ημερολόγια. Περιέχει επιπλέον πληροφορίες όπως η περιγραφή του ημερολογίου, ο ιδιοκτήτης κτλ.
|
|
||||||
|
|
||||||
\item Λίστα Ημερολογίων (Calendar List) - αντιπροσωπεύει μια λίστα με όλα τα ημερολόγια ενός χρήστη της υπηρεσίας αυτής.
|
|
||||||
|
|
||||||
\item Ρύθμιση (Setting) - αντιπροσωπεύει μια επιλογή του χρήστη, η οποία επηρεάζει τον τρόπο λειτουργίας της υπηρεσίας (πχ ρύθμιση ζώνης ώρας).
|
|
||||||
|
|
||||||
\item ACL (Access Control Rule) - αντιπροσωπεύει έναν κανόνα πρόσβασης του ημερολογίου (όπως παραδείγματος χάρη το αν το ημερολόγιο είναι δημόσιο ή ιδιωτικό).
|
|
||||||
|
|
||||||
\item Χρώμα (Color) - αντιπροσωπεύει το χρώμα για κάποια στοιχεία στο περιβάλλον χρήστη της εφαρμογής και τα συμβάντα.
|
|
||||||
|
|
||||||
\item Ελεύθερος / Απασχολημένος (Free / Busy) - αντιπροσωπεύει μια χρονική περίοδο στο ημερολόγιο όπου ο χρήστης είναι είτε απασχολημένος είτε ελεύθερος. Αν είναι απασχολημένος δεν μπορούν να υπάρχουν συμβάντα
|
|
||||||
σε αυτό το διάστημα.
|
|
||||||
\end{itemize}
|
|
||||||
|
|
||||||
Το API της Google λειτουργεί με “resources” και “collections” για να χειριστεί τις προαναφερθέντες έννοιες. Ένα resource αντιπροσωπεύει μια συγκεκριμένη οντότητα η οποία περιέχει δεδομένα για την εφαρμογή. Πολλά resource μαζί απαρτίζουν ένα collection το οποίο περιέχει πολλές χρήσιμες μεθόδους μαζικής διαχείρισης δεδομένων.
|
|
||||||
|
|
||||||
Οι προγραμματιστές διαμορφώνουν τον κωδικά τους έτσι ώστε να είναι συμβατός με αυτήν την δομή και έτσι η επικοινωνία με την υπηρεσία της Google να είναι ευκολότερη.
|
|
||||||
|
|
||||||
\section {Πως χρησιμοποιείται}
|
|
||||||
Η χρήση του API μπορεί να γίνει απευθείας με κλήσεις RESTful προς τον server της Google, είτε με χρήση κάποιων από τις έτοιμες βιβλιοθήκες που παρέχει η εταιρεία. Επίσης είναι απαραίτητη η ύπαρξη ενός λογαριασμού στην Google καθώς και η καταχώρηση του project στο Google API Console έτσι ώστε να πάρει ο προγραμματιστής ένα API Key, ένα κλειδί το οποίο είναι απαραίτητο για την χρήση της υπηρεσίας.
|
|
||||||
|
|
||||||
Αν ο προγραμματιστής επιλέξει την χρήση της RESTful μεθόδου επικοινωνίας θα χρειαστεί να στέλνει request σε διάφορα URL και έτσι να παίρνει απαντήσεις με τα δεδομένα που χρειάζεται. Όλες οι απαντήσεις είναι σε JSON μορφή οπότε θα χρειαστεί να τις αναλύσει (parse) πριν τις χρησιμοποιήσει στην εφαρμογή του.
|
|
||||||
|
|
||||||
Δείγματα από URL για την κλήση διαφόρων μεθόδων:
|
|
||||||
|
|
||||||
\begin{lstlisting}[breaklines=true]
|
|
||||||
https://www.googleapis.com/calendar/v3/lists/calendarListID/calendar?parameters
|
|
||||||
https://www.googleapis.com/calendar/v3/users/userID/lists?parameters
|
|
||||||
\end{lstlisting}
|
|
||||||
|
|
||||||
Αντιθέτως με την χρήση των έτοιμων βιβλιοθηκών οι διαδικασίες επικοινωνίας είναι έτοιμες και ο προγραμματιστής μπορεί να πετύχει την επικοινωνία με τους servers της Google γρηγορότερα και ευκολότερα.
|
|
||||||
Υπάρχουν βιβλιοθήκες για την Java, την PHP, την Python, το .NET περιβάλλον και την Ruby και πολλές άλλες γλώσσες και τεχνολογίες.
|
|
||||||
|
|
||||||
Αφού γίνει λήψη των βιβλιοθηκών και συμπερίληψη στον κώδικα του project, μπορούν να χρησιμοποιηθούν μέσα από τον κώδικα:
|
|
||||||
|
|
||||||
\begin{lstlisting}
|
|
||||||
require_once "../src/apiClient.php";
|
|
||||||
require_once "../src/contrib/apiCalendarService.php";
|
|
||||||
\end{lstlisting}
|
|
||||||
|
|
||||||
Στην συνέχεια είναι απαραίτητο να γίνει ρύθμιση κάποιων παραμέτρων έτσι ώστε να μπορέσει να γίνει χρήση της υπηρεσίας:
|
|
||||||
|
|
||||||
\begin{lstlisting}[breaklines=true]
|
|
||||||
global $apiConfig;
|
|
||||||
|
|
||||||
$apiConfig = array(
|
|
||||||
// Site name to show in Google's OAuth authentication screen
|
|
||||||
'site_name' => 'www.example.org',
|
|
||||||
|
|
||||||
// OAuth2 Setting, you can get these keys on the API Access tab on
|
|
||||||
// the Google APIs Console
|
|
||||||
'oauth2_client_id' => 'YOUR_CLIENT_ID',
|
|
||||||
'oauth2_client_secret' => 'YOUR_CLIENT_SECRET',
|
|
||||||
'oauth2_redirect_uri' => 'YOUR_REDIRECT_URL',
|
|
||||||
|
|
||||||
// The developer key; you get this from the Google APIs Console
|
|
||||||
'developer_key' => 'YOUR_DEVELOPER_KEY',
|
|
||||||
...
|
|
||||||
|
|
||||||
// Which Authentication, Storage and HTTP IO classes to use.
|
|
||||||
'authClass' => 'apiOAuth2',
|
|
||||||
....
|
|
||||||
|
|
||||||
// Definition of service specific values like scopes, OAuth token URLs, etc
|
|
||||||
'services' => array(
|
|
||||||
'calendar' => array('scope' => 'https://www.googleapis.com/auth/calendar'),
|
|
||||||
)
|
|
||||||
);
|
|
||||||
\end{lstlisting}
|
|
||||||
|
|
||||||
Έπειτα θα χρειαστεί να γίνει εκκίνηση του service και να ολοκληρωθεί η διαδικασία πιστοποίησης (authenticate) με την χρήση του API Key που αντιστοιχεί στην εφαρμογή.
|
|
||||||
|
|
||||||
\begin{lstlisting}[breaklines=true]
|
|
||||||
<?php
|
|
||||||
session_start();
|
|
||||||
|
|
||||||
require_once "../src/apiClient.php";
|
|
||||||
require_once "../src/contrib/apiCalendarService.php";
|
|
||||||
|
|
||||||
$apiClient = new apiClient();
|
|
||||||
$apiClient->setUseObjects(true);
|
|
||||||
$service = new apiCalendarService($apiClient);
|
|
||||||
|
|
||||||
if (isset($_SESSION['oauth_access_token'])) {
|
|
||||||
$apiClient->setAccessToken($_SESSION['oauth_access_token']);
|
|
||||||
} else {
|
|
||||||
$token = $apiClient->authenticate();
|
|
||||||
$_SESSION['oauth_access_token'] = $token;
|
|
||||||
}
|
|
||||||
...
|
|
||||||
\end{lstlisting}
|
|
||||||
|
|
||||||
Με αυτόν τον τρόπο εκτελούνται οι διαδικασίες ανταλλαγής δεδομένων μεταξύ του Google Calendar και του συστήματος του προγραμματιστή.
|
|
||||||
|
|
||||||
\section{Συγχρονισμός ραντεβού}
|
|
||||||
Ο συγχρονισμός δεδομένων μεταξύ δυο συστημάτων είναι μια περίπλοκη και πολλές φορές υποτιμημένη διαδικασία, διότι ο προγραμματιστής έχει να κάνει αρκετή δουλειά έτσι ώστε να καταφέρει να γεφυρώσει και τις δυο πηγές δεδομένων με τον καλύτερο δυνατό τρόπο. Το αποτέλεσμα δεν μπορεί ποτέ να είναι 100\% επιτυχές διότι μερικές φορές τα δεδομένα και οι αλλαγές μπορεί να έρχονται σε σύγκρουση (conflict) και έτσι θα χρειαστεί να παρθούν αποφάσεις είτε με βάση κάποιους κανόνες προτεραιότητας, είτε από τον ίδιο τον χρήστη για το ποια αλλαγή θα υπερισχύσει εν τέλη. Το πράγμα μάλιστα δυσκολεύει περισσότερο όταν δεν υπάρχει πρόσβαση στον κώδικα του ενός από τα δύο συστήματα (πχ Google Calendar) και όλη η διαδικασία θα πρέπει να τρέξει από την μια πλευρά.
|
|
||||||
|
|
||||||
Στην περίπτωση του Easy!Appointments έχει υλοποιηθεί μια διαδικασία η οποία συγχρονίζει τα ραντεβού και τα συμβάντα του συστήματος με αυτά του Google Calendar. Η διαδικασία αυτή εκτελείται όταν δημιουργούνται συγκεκριμένα συμβάντα (πχ. προσθήκη ραντεβού) και φέρνει και τα δύο ημερολόγια στην ίδια κατάσταση. Ο συγχρονισμός εκτελείται κάθε φορά για το πλάνο ενός πάροχου υπηρεσιών και εφόσον έχει ήδη δοθεί η άδεια στην εφαρμογή να έχει πρόσβαση στα δεδομένα του Google Calendar, για τον συγκεκριμένου χρήστη.
|
|
||||||
|
|
||||||
Με αυτόν τον τρόπο τα ραντεβού και οι αλλαγές που θα γίνονται από τα δυο συστήματα θα συγχωνεύονται και ο χρήστης θα μπορεί να τα διαχειρίζεται και από τις δύο πλευρές. Το μόνο πρόβλημα είναι ότι από την πλευρά του Google Calendar δεν είναι δυνατό να εκκινηθεί η διαδικασία του συγχρονισμού και έτσι αυτό θα πρέπει να γίνεται πάντοτε από την πλευρά του Easy!Appointments.
|
|
||||||
|
|
||||||
Η διαδικασία αυτή θα μπορούσε να αυτοματοποιηθεί με την χρήση της μεθόδου cron job, αλλά κάτι τέτοιο θα μπορούσε να αποφέρει επιπλέον προβλήματα, μιας και είναι απαραίτητο ο χρήστης να έχει τα κατάλληλα δικαιώματα στον server για να το κάνει και αυτό δεν είναι πάντα εφικτό. Οπότε η μέθοδος αυτή απορρίπτεται λόγο αυτής της δυσκολίας.
|
|
||||||
|
|
||||||
Η μέθοδος συγχρονισμού του Easy!Appointments είναι αμφίδρομη. Με την έννοια αυτή εννοείται ότι συγχρονίζονται τόσο οι αλλαγές που γίνονται στο Easy!Appointments, όσο και οι αλλαγές που γίνονται από το Google Calendar, προσφέροντας έτσι μεγαλύτερη ελευθερία και προσβασιμότητα στα δεδομένα των χρηστών της εφαρμογής. Παρακάτω αναλύονται τα βήματα που ακολουθούνται κατά την διαδικασία του συγχρονισμού.
|
|
||||||
|
|
||||||
\begin{enumerate}
|
|
||||||
\item Η διαδικασία χωρίζεται σε δύο μέρη. Το πρώτο μέρος έχει να κάνει με τον συγχρονισμό μιας ενέργειας που μόλις έχει γίνει στο Easy!Appointments (πχ ένας πελάτης πραγματοποίησε μια κράτηση στο πλάνο ενός πάροχου υπηρεσιών). Το καινούργιο αυτό ραντεβού που μόλις καταχωρήθηκε στο σύστημα θα χρειαστεί να ενσωματωθεί και στο Google Calendar. Έτσι τρέχει μια διαδικασία η οποία προσθέτει αυτό το ραντεβού στην υπηρεσία της Google.
|
|
||||||
\item Εκτός όμως του ραντεβού που δημιουργήθηκε στο Easy!Appointments, θα χρειαστεί να ληφθούν και οι αλλαγές που έχουν γίνει στο Google Calendar. Για αυτόν τον λόγο είναι απαραίτητο να ανιχνευθούν όλα τα καταχωρημένα ραντεβού και να ελεγχθούν για τυχόν αλλαγές. Επειδή αυτό όμως μπορεί να γίνει αρκετά χρονοβόρο υπάρχει μια παράμετρος στο σύστημα του Easy!Appointments η οποία καθορίζει το χρονικό διάστημα στο παρελθόν και το μέλλον για το οποίο θέλει ο χρήστης να εκτελείται ο συγχρονισμός. Επίσης τα ραντεβού που έχουν συγχρονιστεί με το Google Calendar έχουν κρατημένο το id της εγγραφής στο σύστημα της Google, έτσι ώστε να είναι δυνατό να ανιχνευθούν οι αλλαγές που έχουν γίνει από τον χρήστη. Έτσι αν για παράδειγμα ένας χρήστης διαγράψει ένα ραντεβού από το Google Calendar το οποίο ήταν συγχρονισμένο και στο Easy!Appointments, η διαδικασία του συγχρονισμού θα καταλάβει ότι το ραντεβού λείπει και έτσι θα το διαγράψει και από το σύστημα του Easy!Appointments.
|
|
||||||
\end{enumerate}
|
|
|
@ -1,71 +0,0 @@
|
||||||
\documentclass[oneside, 12pt]{book}
|
|
||||||
|
|
||||||
%% ============================================================================
|
|
||||||
%% ΟΡΙΣΜΟΣ ΤΩΝ PACKAGES ΠΟΥ ΘΑ ΧΡΗΣΙΜΟΠΟΙΗΘΟΥΝ
|
|
||||||
%% ============================================================================
|
|
||||||
\usepackage{thesis}
|
|
||||||
\usepackage{tabularx}
|
|
||||||
\usepackage{epsfig}
|
|
||||||
\usepackage{float}
|
|
||||||
\usepackage{listings}
|
|
||||||
\usepackage{hyperref}
|
|
||||||
\usepackage{color}
|
|
||||||
\usepackage{xcolor}
|
|
||||||
\usepackage[backend=biber]{biblatex}
|
|
||||||
|
|
||||||
%% ============================================================================
|
|
||||||
%% ΡΥΘΜΙΣΗ ΤΩΝ HYPERLINKS
|
|
||||||
%% ============================================================================
|
|
||||||
\hypersetup {colorlinks}
|
|
||||||
\definecolor{darkred}{rgb}{0.5,0,0}
|
|
||||||
\definecolor{darkgreen}{rgb}{0,0.5,0}
|
|
||||||
\definecolor{darkblue}{rgb}{0,0,0.5}
|
|
||||||
\hypersetup{
|
|
||||||
colorlinks,
|
|
||||||
linkcolor=darkblue,
|
|
||||||
filecolor=darkgreen,
|
|
||||||
urlcolor=darkblue,
|
|
||||||
citecolor=darkred
|
|
||||||
}
|
|
||||||
|
|
||||||
%% ============================================================================
|
|
||||||
%% PHP LISTINGS STYLE
|
|
||||||
%% http://tex.stackexchange.com/a/54687
|
|
||||||
%% http://en.wikibooks.org/wiki/LaTeX/Source_Code_Listings
|
|
||||||
%% http://en.wikibooks.org/wiki/LaTeX/Colors
|
|
||||||
%% ============================================================================
|
|
||||||
\definecolor{dkgreen}{rgb}{0,.6,0}
|
|
||||||
\definecolor{dkblue}{rgb}{0,0,.6}
|
|
||||||
\definecolor{dkyellow}{cmyk}{0,0,.8,.3}
|
|
||||||
\definecolor{ltgrey}{RGB}{240,240,240}
|
|
||||||
\lstset{
|
|
||||||
language = php,
|
|
||||||
basicstyle = \footnotesize\ttfamily,
|
|
||||||
keywordstyle = \color{dkblue},
|
|
||||||
stringstyle = \color{red},
|
|
||||||
identifierstyle = \color{dkgreen},
|
|
||||||
commentstyle = \color{gray},
|
|
||||||
emph =[1]{php},
|
|
||||||
emphstyle =[1]\color{black},
|
|
||||||
emph =[2]{if,and,or,else,public,function,try,catch,return},
|
|
||||||
emphstyle =[2]\color{dkblue},
|
|
||||||
numbers = left,
|
|
||||||
tabsize = 2,
|
|
||||||
backgroundcolor = \color{ltgrey},
|
|
||||||
extendedchars = true,
|
|
||||||
showspaces = false,
|
|
||||||
showstringspaces= false}
|
|
||||||
|
|
||||||
%% ============================================================================
|
|
||||||
%% ΤΑ ΠΑΡΑΚΑΤΩ ΕΙΝΑΙ ΥΠΟΧΡΕΩΤΙΚΑ
|
|
||||||
%% ============================================================================
|
|
||||||
\renewcommand{\thesistitle}{Δημιουργία διαδικτυακού συστήματος συναντήσεων (appointments) με χρήση Google Calendar PHP API}
|
|
||||||
\renewcommand{\thesisauthor}{Αλέξανδρος Τσελεγγίδης (2503)}
|
|
||||||
\renewcommand{\thesisauthorabbrv}{Α. Τσελεγγίδης}
|
|
||||||
\renewcommand{\thesisauthorinitials}{ΑΤ}
|
|
||||||
\renewcommand{\thesissupervisor}{Δρ. Νικόλαος Πεταλίδης, Επιστημονικός Συνεργάτης}
|
|
||||||
\renewcommand{\thesismonth}{Νοέμβριος}
|
|
||||||
\renewcommand{\thesisyear}{2013}
|
|
||||||
|
|
||||||
%% ΒΙΒΛΙΟΓΡΑΦΙΑ
|
|
||||||
\addbibresource{thesis.bib}
|
|
|
@ -1,198 +0,0 @@
|
||||||
%% ΣΧΕΔΙΑΣΗ & ΥΛΟΠΟΙΗΣΗ
|
|
||||||
%% Σε αυτό το κεφάλαιο περιγράφεται η διαδικασία σχεδίασης και
|
|
||||||
%% υλοποίησης της εφαρμογής. Αναλύονται οι επιλογές που έχουν
|
|
||||||
%% γίνει και με ποιόν τρόπο λειτουργούν κάποια βασικά τμήματα
|
|
||||||
%% του κώδικα.
|
|
||||||
|
|
||||||
\chapter{Σχεδίαση \& Υλοποίηση}
|
|
||||||
Σε αυτό το κεφάλαιο γίνεται ανάλυση του συστήματος στα επιμέρους μέρη που το απαρτίζουν και περιγράφεται η διαδικασία της υλοποίησης τους. Επεξηγούνται τα σημαντικότερα σημεία στον κώδικα και οι αλγόριθμοι που χρησιμοποιούνται για την επίλυση των κυριότερων λειτουργιών. Έχουν συμπεριληφθεί τμήματα κώδικα αλλά και διαγράμματα τα οποία βοηθούν στην κατανόηση των λύσεων που επιλέχθηκαν για την ολοκλήρωση της εφαρμογής.
|
|
||||||
|
|
||||||
%% ==================================================
|
|
||||||
%% ΑΝΑΛΥΣΗ ΔΕΔΟΜΕΝΩΝ
|
|
||||||
%% ==================================================
|
|
||||||
\section{Ανάλυση δεδομένων}
|
|
||||||
Το κυριότερο πρόβλημα που προσπαθεί να λύσει το σύστημα είναι η κράτηση και η διαχείριση ραντεβού από μια επιχείριση. Σε αυτήν την περίπτωση χρήσης έχει επικεντρωθεί η σχεδίαση και η υλοποίηση του συστήματος το οποίο περιέχει και άλλες δυνατότητες οι οποίες μπορούν όμως να θεωρηθούν λιγότερο σημαντικές. Έχοντας υπόψιν την έννοια "ραντεβού" ως την κύρια οντότητα της εφαρμογής, σχεδιάστηκε το παρακάτω μοντέλο το οποίο διευκρινίζει τις σχέσεις των οντοτήτων του συστήματος μεταξύ τους.
|
|
||||||
|
|
||||||
\begin{figure}[ht!]
|
|
||||||
\centering
|
|
||||||
\includegraphics[width=160mm]{images/domain-model.png}
|
|
||||||
\caption{Domain model του συστήματος.}
|
|
||||||
\label{domain-model}
|
|
||||||
\end{figure}
|
|
||||||
|
|
||||||
Με βάση αυτό το σχεδιάγραμμα μπορεί πολύ εύκολα να προκύψει και το σχεσιακό μοντέλο της βάσης δεδομένων δεδομένου ότι έχουμε τις οντότητες αλλά και τις σχέσεις μεταξύ τους. Όλοι οι χρήστες κληρονομούν την συμπεριφορά τους από μια οντότητα (User) και επιπρόσθετα κατέχουν διάφορες ιδιότητες που είναι αναγκαίες για τον ρόλο τους μέσα στην εφαρμογή. Για παράδειγμα ο χρήστης γραμματέας (Secretary) περιέχει έναν πίνακα από πάροχους (Providers) τους οποίους μπορεί να διαχειριστεί όπως και ένα ραντεβού είναι ξεκάθαρο ότι περιέχει στην πληροφορία του έναν πελάτη, έναν πάροχο και μια υπηρεσία.
|
|
||||||
|
|
||||||
\begin{figure}[ht!]
|
|
||||||
\centering
|
|
||||||
\includegraphics[width=160mm]{images/er.png}
|
|
||||||
\caption{Σχεσιακό μοντέλο της βάσης δεδομένων (ER).}
|
|
||||||
\label{er}
|
|
||||||
\end{figure}
|
|
||||||
|
|
||||||
Για την διαχείριση των δεδομένων της βάσης δημιουργήθηκαν ειδικές κλάσεις (models) οι οποίες περιέχουν μεθόδους που χρησιμοποιούνται από τους controllers του συστήματος. Το CodeIgniter δίνει στον προγραμματιστή ένα δικό του μέσο επικοινωνίας με την βάση δεδομένων, το οποίο είναι ένα πολύ ισχυρό και ευέλικτο εργαλείο. Η επονομαζόμενη Database Class του CodeIgniter επιτρέπει στον προγραμματιστή να εκτελεί ερωτήματα προς την βάση, να παράγει αποτελέσματα και να τα αναλύει σε ξεχωριστές εγγραφές, να κρατάει στην μνήμη ερωτήματα για γρηγορότερη ανταπόκριση (query caching) και κυριότερο την κλάση Active Record. Η κλάση αυτή έχει έναν δικό της τρόπο για την εκτέλεση των ερωτημάτων προς την βάση. Όλα τα τμήματα ενός τυπικού ερωτήματος είναι μέθοδοι οι οποίες χρησιμοποιούνται από τον προγραμματιστή ως το μέσο επικοινωνίας με την βάση δεδομένων. Το θετικό είναι ότι ανεξαρτήτως τον τύπο της βάσης η κλάση αυτή λειτουργεί με τον ίδιο τρόπο (MySQL, PostgreSQL, MSSQL κτλ). Η τεχνική αυτή λέγεται Active Record Database Pattern και έχει να κάνει με την αλλαγή adapter στην κλάση ανάλογα με τον τύπο της βάσης. Σε κάθε περίπτωση όμως ο τρόπος χρήσης της Active Record Class είναι ο ίδιος. Στο παρακάτω τμήμα κώδικα αναφέρεται ένα παράδειγμα για το πως μπορεί να βρεθεί το αναγνωριστικό μιας εγγραφής χρησιμοποιώντας ως κλειδί την διεύθυνση email.
|
|
||||||
|
|
||||||
\lstinputlisting{snippets/find_record_id.php}
|
|
||||||
|
|
||||||
%% ==================================================
|
|
||||||
%% ΑΡΧΙΤΕΚΤΟΝΙΚΗ ΚΩΔΙΚΑ
|
|
||||||
%% ==================================================
|
|
||||||
\section{Αρχιτεκτονική κώδικα}
|
|
||||||
Η εφαρμογή είναι γραμμένη χρησιμοποιώντας τις εξής τεχνολογίες: PHP, JavaScript, HTML, CSS, MySQL. Εκτός αυτών έχουν χρησιμοποιηθεί και κάποια βοηθητικά εργαλεία τα οποία διευκολύνουν τον προγραμματιστή στο να πετύχει καλύτερο αποτέλεσμα σε μικρότερο χρόνο. Αυτά τα εργαλεία (frameworks) όπως έχουν αναφερθεί και σε προηγούμενο κεφάλαιο είναι τα CodeIgniter (PHP), jQuery (JavaScript), Bootstrap (CSS + JavaScript).
|
|
||||||
|
|
||||||
Όσον αφορά την αρχιτεκτονική του κώδικα έχει επιλεχθεί το μοντέλο MVC (Model - View - Controller) το οποίο υλοποιείται με άριστη απόδοση και οργάνωση χάρη στο framework CodeIgniter. Ο κώδικας PHP έχει χωριστεί σε τρία μέρη (models, views, controllers) και με αυτόν τον τρόπο παραμένει σε όλο τον κώδικα της εφαρμογής. Ο διαχωρισμός αυτός βελτιώνει τις συνθήκες συντήρησης γιατί είναι ξεκάθαρο σε ποιο από τα τρία ξεχωριστά σημεία ανήκει μια λειτουργία, όταν αυτή αναζητείται από τον προγραμματιστή. Έχουν συγγραφεί και δοκιμαστεί κλάσεις models για κάθε οντότητα οι οποίες αναλαμβάνουν την διαχείριση των δεδομένων με την βάση και παρέχουν μεθόδους που επαναχρησιμοποιούνται σε διάφορες περιπτώσεις. Επίσης έχουν δημιουργηθεί views για κάθε σελίδα που μπορεί να δει ο χρήστης τα οποία συνδέονται με ένα κομμάτι CSS κώδικα, υπεύθυνο για την μορφοποίησή τους. Τέλος τον συντονισμό αυτών των τμημάτων αναλαμβάνουν οι κλάσεις controllers οι οποίες είτε είναι υπεύθυνες για την σωστή φόρτωση μιας σελίδας της εφαρμογής, είτε απαντούν σε κλήσεις της JavaScript που γίνονται μέσω της τεχνολογίας AJAX.
|
|
||||||
|
|
||||||
Πολύ μεγάλο μέρος της εφαρμογής έχει γραφεί σε JavaScript για να μπορέσει το περιβάλλον εργασίας του χρήστη να γίνει αρκετά φιλικό και λειτουργικό. Ο JavaScript κώδικας χωρίζεται σε διάφορες κλάσεις και namespace τα οποία χρησιμοποιούνται από μια ή και παραπάνω σελίδες και στόχο έχουν να "ζωντανέψουν" το περιεχόμενο προσθέτοντας διαδραστικότητα. Πολλές φορές είναι απαραίτητο να εκτελεστούν κλήσεις AJAX προς τον server για την λήψη πρόσθετων πληροφοριών, είτε για να αποσταλούν δεδομένα τα οποία σηματοδοτούν για παράδειγμα κάποια επεξεργασία ή και διαγραφή εγγραφής από την βάση δεδομένων. Η χρήση του AJAX κρίνεται σημαντική διότι με αυτήν αποφεύγονται οι συνεχείς επαναφορτώσεις των σελίδων, οι οποίες θα γινόταν για να μπορέσει ο client να επικοινωνήσει με τον server. Αυτό το κομμάτι αναλαμβάνεται εξ ολοκλήρου από την JavaScript και προσδίδει ευελιξία και ταχύτητα στην χρήση της εφαρμογής. Το framework jQuery αποτελεί σημαντικό εργαλείο για την διεκπεραίωση διαφόρων λειτουργιών μέσω της JavaScript διότι δίνει την δυνατότητα στον προγραμματιστή να γράψει κώδικα όμορφα δομημένο και πολύ πιο αποδοτικό από ότι θα ήταν χωρίς την χρήση του. Αυτή η ιδιότητα της βιβλιοθήκης συντελεί και στην δημοτικότητά της και την χρήση της από κολοσσούς ανάπτυξης λογισμικού.
|
|
||||||
|
|
||||||
Για την μορφοποίηση των σελίδων της εφαρμογής χρησιμοποιήθηκε το πιο διαδεδομένο CSS framework την συγκεκριμένη την περίοδο, το Bootstap. Χρησιμοποιώντας αυτό το framework γράφτηκε νέο CSS το οποίο μορφοποιεί τις σελίδες έτσι ώστε να ανταποκρίνονται όπως πρέπει σε διάφορα μεγέθη οθονών, ενώ παράλληλα δεν χαλάει την συμβατότητα μεταξύ των διάφορων περιηγητών διαδικτύου. Το Bootstrap περιέχει και κάποια πρόσθετα JavaScript τα οποία βοηθούν σημαντικά στο οπτικό αποτέλεσμα της διεπαφής χρήστη.
|
|
||||||
|
|
||||||
Στο παρακάτω σχεδιάγραμμα γίνεται σαφής ο διαχωρισμός του κώδικα του συστήματος στα διάφορα τμήματα που το απαρτίζουν και η χρήση των εξωτερικών εργαλείων που συντέλεσαν στην ορθή ανάπτυξη της εφαρμογής.
|
|
||||||
|
|
||||||
\begin{figure}[ht!]
|
|
||||||
\centering
|
|
||||||
\includegraphics[width=100mm]{images/system-architecture.png}
|
|
||||||
\caption{Τα τμήματα που απαρτίζουν το Easy!Appointments.}
|
|
||||||
\label{system-architecture}
|
|
||||||
\end{figure}
|
|
||||||
|
|
||||||
%% ==================================================
|
|
||||||
%% ΥΛΟΠΟΙΗΣΗ ΣΥΣΤΗΜΑΤΟΣ
|
|
||||||
%% ==================================================
|
|
||||||
\section{Υλοποίηση συστήματος}
|
|
||||||
Εφόσον ο αρχικός σχεδιασμός είχε ολοκληρωθεί ξεκίνησε η υλοποίηση της εφαρμογής με πρώτη εργασία τον σχεδιασμό της βάσης δεδομένων. Έχοντας ήδη σχεδιασμένο το domain model η δημιουργία του σχήματος της βάσης έγινε γρήγορα και διατηρήθηκε ως την ολοκλήρωση του έργου με μικρές προσθήκες όπου ήταν απαραίτητο.
|
|
||||||
|
|
||||||
Στην συνέχεια, πριν γραφεί κώδικας θα έπρεπε να γίνει η επιλογή και το στήσιμο των εξωτερικών βιβλιοθηκών που θα κρίνονταν απαραίτητα για την λειτουργία του συστήματος. Σε αυτήν την φάση επιλέχθηκαν οι βασικές βιβλιοθήκες (CodeIgniter, Google API Library, jQuery, Bootstrap) καθώς και η σημαντικότερη περίπτωση χρήσης για να υλοποιηθεί πρώτη. Αυτή δεν ήταν άλλη από την κράτηση ενός ραντεβού από τον πελάτη. Αυτή η απόφαση πάρθηκε γιατί με αυτόν τον τρόπο θα καθορίζονταν εν μέρη και η αρχιτεκτονική του συστήματος καθώς αυτό θα εξελισσόταν σταδιακά με την ολοκλήρωση και των υπόλοιπων περιπτώσεων χρήσης.
|
|
||||||
|
|
||||||
Η κύρια ροή εργασιών ως προς την υλοποίηση μιας περίπτωσης χρήσης αποτελείται από τα παρακάτω βήματα:
|
|
||||||
\begin{enumerate}
|
|
||||||
\item Συγγραφή της κλάσης model για την συγκεκριμένη οντότητα. Μερικές φορές αυτή η διαδικασία μπορεί να συμπεριλάμβανε και την δημιουργία model και για άλλες οντότητες που εμπλέκονταν στην περίπτωση χρήσης, έτσι ώστε να μπορέσει να λειτουργήσει σωστά ο κώδικας συνολικά. Οι περισσότερες κλάσεις ακολουθούν το ίδιο πρότυπο σχεδίασης και μεθόδων με μικρές διαφοροποιήσεις ανάλογα με την οντότητα που διαχειρίζονται.
|
|
||||||
\item Έλεγχος των model με δημιουργία unit tests. Μετά την ολοκλήρωση των model αυτά θα έπρεπε να δοκιμαστούν έτσι ώστε να διασφαλιστεί η σωστή λειτουργία τους. Εκτός αυτού όμως η συγγραφή unit test είναι και μια καλή ευκαιρία ως παράδειγμα της χρήσης των model από το υπόλοιπο σύστημα. Αν εντοπιζόταν κάποιο πρόβλημα κατά την εκτέλεση των test αυτό διορθωνόταν και τα test εκτελούνταν πάλι έως ότου να ολοκληρωθούν όλα με επιτυχία.
|
|
||||||
\item Εφόσον τα model ήταν ολοκληρωμένα στην συνέχεια δημιουργήθηκαν οι controllers και οι αντίστοιχες συναρτήσεις που θα ήταν υπεύθυνες για την λειτουργία του view που αντιστοιχούσε στην εκάστοτε περίπτωση χρήσης. Έτσι εκτός από τις συναρτήσεις που αναλάμβαναν να φορτώσουν μια σελίδα της εφαρμογής συγκεντρώνοντας τα δεδομένα που ήταν απαραίτητα, υλοποιήθηκαν και οι κλήσεις AJAX που ήταν απαραίτητες από την JavaScript. Αυτές οι κλήσεις συνήθως αναλάμβαναν την διεκπεραίωση κάποιας ενέργειας προς την βάση δεδομένων και επέστρεφαν πάντα κάποιο αποτέλεσμα για να μπορέσει να συνεχίσει την λειτουργία της το τμήμα της JavaScript.
|
|
||||||
\item Στην συνέχεια υλοποιούνταν το αντίστοιχο view που θα έβλεπε ο χρήστης. Σε αυτό τοποθετούνταν ο κώδικας PHP, HTML και η μορφοποίηση της σελίδας (CSS) γραφόταν στο αντίστοιχο αρχείο έτσι ώστε να παραχθεί ένα καλαίσθητο και φιλικό αποτέλεσμα.
|
|
||||||
\item Όταν το view ήταν έτοιμο θα έπρεπε να του προστεθεί και κάποια λειτουργικότητα έτσι ώστε να μπορεί να ανταποκριθεί στις ενέργειες του χρήστη. Για κάθε σελίδα χρησιμοποιούνται μια πληθώρα από βιβλιοθήκες, namespaces, κλάσεις και πρόσθετα JavaScript. Στα αντίστοιχα αρχεία τοποθετήθηκε ο κώδικας που θα ρύθμιζε την λειτουργία της σελίδας και τις ασύγχρονες κλήσεις προς τον server (AJAX).
|
|
||||||
\item Τέλος εφόσον όλα ήταν έτοιμα και η περίπτωση χρήσης είχε υλοποιηθεί χωρίς προβλήματα, όλος ο κώδικας που είχε γραφεί έπρεπε να εξεταστεί (review) για τυχόν προβλήματα λογικής και για την βελτίωση της απόδοσης του, μικραίνοντας όσο είναι δυνατόν την σύζευξη και αυξάνοντας την συνοχή.
|
|
||||||
\end{enumerate}
|
|
||||||
|
|
||||||
Εδώ θα χρειαστεί να αναφερθεί ότι όλες οι κλήσεις AJAX που αφορούν το backend έχουν μεταφερθεί σε μια κλάση controller ξεχωριστά από τον κύριο controller του backend για να είναι καλύτερα οργανωμένες. Αν μελλοντικά ο αριθμός τους και η πολυπλοκότητα τους αυξηθεί τότε θα χρειαστεί να διαιρεθούν ξανά για να μπορέσουν να συντηρούνται πιο εύκολα.
|
|
||||||
|
|
||||||
%% ==================================================
|
|
||||||
%% ΠΕΡΙΓΡΑΦΗ ΒΑΣΙΚΩΝ ΑΛΓΟΡΙΘΜΩΝ
|
|
||||||
%% ==================================================
|
|
||||||
\section{Περιγραφή βασικών αλγορίθμων}
|
|
||||||
Σε αυτήν την ενότητα θα γίνει ανάλυση κάποιων βασικών αλγορίθμων που αποτελούν κρίσιμα τμήματα για την λειτουργία του συστήματος. Η περιγραφή θα γίνει σχολιάζοντας τα τμήματα κώδικα που απαρτίζουν αυτούς τους αλγορίθμους αναφέροντας και τις συγκεκριμένες γραμμές στα οποία αναφέρονται. Στην επόμενη ενότητα παρέχονται κάποια σχεδιαγράμματα τα οποία μπορούν να βοηθήσουν στην κατανόηση αυτών των αλγορίθμων.
|
|
||||||
|
|
||||||
\subsection{Πλήρης συγχρονισμός με το Google Calendar}
|
|
||||||
Η διαδικασία του πλήρη συγχρονισμού των ραντεβού με το Google Calendar αποτελεί ένας από τους κυριότερους αλγορίθμους του Easy!Appointments. Η πολυπλοκότητα της διαδικασίας συγχρονισμού δεδομένων κατέστησαν την υλοποίηση αυτού του τμήματος κώδικα αρκετά ενδιαφέρον και το αποτέλεσμα κατάφερε να καλύψει τις αρχικές απαιτήσεις. Μπορεί μελλοντικά να υπάρξουν βελτιώσεις στον κώδικα αλλά την συγκεκριμένη στιγμή ο αλγόριθμος λειτουργεί επιτυχώς και συγχρονίζει τα ραντεβού του συστήματος με τα συμβάντα που έχει περάσει ο χρήστης στο Google Calendar.
|
|
||||||
|
|
||||||
\lstinputlisting{snippets/google_sync_algorithm.php}
|
|
||||||
|
|
||||||
Η μέθοδος αυτή καλείται κάθε φορά που πρέπει να τρέξει ο αλγόριθμος συγχρονισμού για έναν πάροχο υπηρεσιών. Στο πρώτο μέρος του κώδικα ελέγχεται αν ο χρήστης έχει τα δικαιώματα να τρέξει αυτήν την μέθοδο και αν έχει δοθεί το αναγνωριστικό της εγγραφής του πάροχου. Έπειτα φορτώνονται τα απαραίτητα models και γίνεται η λήψη των πληροφοριών του πάροχου από την βάση (γραμμές 17 - 30).
|
|
||||||
|
|
||||||
Για να συνεχιστεί η διαδικασία θα πρέπει να ελεγχθεί αν ο πάροχος έχει ενεργό τον συγχρονισμό με το Google Calendar. Αν η επιλογή αυτή είναι ενεργή τότε ο αλγόριθμος χρησιμοποιεί το token του πάροχου για να πιστοποιήσει την χρήση των δεδομένων του στο Google Calendar, διαφορετικά η διαδικασία τερματίζεται (γραμμές 33 - 43).
|
|
||||||
|
|
||||||
Για να γίνει εξοικονόμηση κλήσεων προς την υπηρεσία της Google αλλά και να μειωθεί ο χρόνος διεκπεραίωσης του αλγορίθμου συγχρονισμού, το χρονικό διάστημα μέσα στο οποίο θα συγχρονισθούν τα δεδομένα περιορίζεται στο εύρος των ημερών που έχει τεθεί ως ρύθμιση για τον κάθε πάροχο (προεπιλεγμένη τιμή 5 ημέρες στο παρελθόν και 5 στο μέλλον). Αυτό είναι το χρονικό διάστημα στο οποίο θα ελεγχθούν όλα τα δεδομένα και από τα δύο συστήματα και θα συντονιστούν έτσι ώστε να είναι τα ίδια (γραμμές 47 - 54).
|
|
||||||
|
|
||||||
Το επόμενο κομμάτι κώδικα αφού πρώτα λάβει τα ραντεβού από την βάση δεδομένων του Easy!Appointments, εξετάζει τις εγγραφές μια προς μια για το αν έχουν συγχρονιστεί με το Google Calendar. Εδώ υπάρχουν οι εξής περιπτώσεις:
|
|
||||||
\begin{enumerate}
|
|
||||||
\item Το ραντεβού δεν έχει ακόμα συγχρονιστεί οπότε θα πρέπει να προστεθεί στο Google Calendar (γραμμές 88 - 93).
|
|
||||||
\item Το ραντεβού είναι συγχρονισμένο και πρέπει να ελεγχθεί αν υπάρχουν διαφορές με το συμβάν που είναι καταχωρημένο στο Google Calendar. Αν ναι τότε αυτό σημαίνει ότι ο χρήστης έχει αλλάξει τα στοιχεία του συμβάντος στο Google Calendar και η εγγραφή του ραντεβού στο Easy!Appointments θα πρέπει να ενημερωθεί (γραμμές 97 - 126).
|
|
||||||
\item Το ραντεβού είναι συγχρονισμένο αλλά δεν έχει βρεθεί στο Google Calendar. Εφόσον δεν έχει βρεθεί η εγγραφή σημαίνει ότι ο χρήστης την έχει διαγράψει από το Google Calendar και έτσι θα πρέπει να διαγραφεί και από το Easy!Appointments (γραμμές 130 - 131).
|
|
||||||
\end{enumerate}
|
|
||||||
Με το πέρας αυτού του τμήματος κώδικα όλα τα ραντεβού του Easy!Appointments θα πρέπει να έχουν συγχρονιστεί με το Google Calendar.
|
|
||||||
|
|
||||||
Τα μη διαθέσιμα διαστήματα χρησιμοποιούνται ως ραντεβού στον συγκεκριμένο αλγόριθμο με την διαφορά ότι δεν υπάρχουν σε αυτά πληοροφίες για κάποιο πελάτη ή υπηρεσία (γραμμές 83 - 84).
|
|
||||||
|
|
||||||
Υπάρχουν όμως συμβάντα στην υπηρεσία της Google τα οποία μπορεί να έχουν προστεθεί απευθείας στο Google Calendar και να μην υπάρχουν στο Easy!Appointments. Σε αυτήν την περίπτωση θα πρέπει να ανιχνευθούν και να εξεταστούν όλα τα συμβάντα που αντιστοιχούν στην χρονική περίοδο συγχρονισμού (5 ημέρες πριν και 5 ημέρες μετά την τρέχουσα ημερομηνία) και να ελεγχθεί αν υπάρχει κάποιο συμβάν που δεν είναι συγχρονισμένο.
|
|
||||||
|
|
||||||
Αυτήν την εργασία αναλαμβάνει το επόμενο κομμάτι κώδικα το οποίο χρησιμοποιώντας την βιβλιοθήκη Google API μπορεί να διαβάσει τα συμβάντα τα οποία βρίσκονται στο Google Calendar. Η διαδικασία ξεκινάει με την λήψη αυτών των συμβάντων τα οποία στην συνέχεια εξετάζονται ένα προς ένα για το αν υπάρχουν στο Easy!Appointments. Αν όχι τότε προστίθενται και συγχρονίζονται και στα δύο συστήματα και έτσι διασφαλίζεται η ακεραιότητα των δεδομένων και στα δύο συστήματα (γραμμές 137 - 159).
|
|
||||||
|
|
||||||
Τέλος η συνάρτηση επιστρέφει την σταθερά AJAX\_SUCCESS την οποία θα διαβάσει η JavaScript και έτσι θα γνωρίζει ότι η διαδικασία έχει ολοκληρωθεί με επιτυχία. Διαφορετικά αν προκύψουν σφάλματα αυτά επιστρέφονται σε JSON μορφή και εμφανίζονται με ένα φιλικό μήνυμα προς τον χρήστη.
|
|
||||||
|
|
||||||
\subsection{Υπολογισμός διαθέσιμων ωρών πάροχου}
|
|
||||||
Ένα κομβικό σημείο στον κώδικα της εφαρμογής είναι ο υπολογισμός των διαθέσιμων ωρών ενός πάρoχου στις οποίες μπορεί ένας πελάτης να κλείσει ένα ραντεβού για μια υπηρεσία, χωρίς να υπάρχει σύγκρουση με άλλα συμβάντα. Για να επιτευχθεί ο υπολογισμός αυτός χρειάζεται να γίνουν αρκετοί έλεγχοι έτσι ώστε τα αποτελέσματα να είναι σωστά και να μην δημιουργούνται προβλήματα με τα πλάνα των πάροχων υπηρεσιών. Η διαδικασία χωρίζεται σε δύο μεθόδους με την πρώτη να υπολογίζει τα ελεύθερα χρονικά διαστήματα του πάροχου και την δεύτερη να υπολογίζει τις ακριβείς ώρες στις οποίες θα μπορεί ο πελάτης να κλείσει ραντεβού.
|
|
||||||
|
|
||||||
\lstinputlisting{snippets/provider_available_periods.php}
|
|
||||||
|
|
||||||
Το πρώτο πράγμα που πρέπει να γίνει είναι η λήψη του πλάνου εργασίας του πάροχου καθώς και των ήδη καταχωρημένων ραντεβού για την επιλεγμένη ημερομηνία. Επίσης υπάρχει και η περίπτωση να πρέπει να αποκλειστούν κάποια ραντεβού κατά τον υπολογισμό των διαθέσιμων ωρών οπότε αν έχουν οριστεί τέτοιες εγγραφές δεν λαμβάνονται υπόψιν στον υπολογισμό. Αυτή η επιλογή είναι απαραίτητη όταν χρειάζεται ο πελάτης να επεξεργαστεί ένα ήδη καταχωρημένο ραντεβού το οποίο δεν θα πρέπει να εμφανίζει ως δεσμευμένη την ώρα που καταλαμβάνει το ίδιο στο ημερολόγιο του πάροχου. Τα στοιχεία αυτά θα χρησιμοποιηθούν έτσι ώστε τα διαθέσιμα διαστήματα που θα υπολογιστούν να αντιπροσωπεύουν τον χρόνο στον οποίο ο πάροχος θα είναι διαθέσιμος (γραμμές 23 - 47).
|
|
||||||
|
|
||||||
Έπειτα θα διαχωριστούν τα ελεύθερα χρονικά διαστήματα του πάροχου από τα διαλείμματα και τα ήδη καταχωρημένα ραντεβού. Αρχικά για την επιλεγμένη ημέρα του ραντεβού ελέγχονται αν υπάρχουν καθόλου διαλείμματα. Αν ναι, τότε τα διαθέσιμα διαστήματα χωρίζονται μεταξύ των διαλειμμάτων του πάροχου (γραμμές 54 - 81) και παράγονται νέα χρονικά διαστήματα. Στην συνέχεια λαμβάνονται υπόψιν τα ραντεβού που έχουν ήδη κρατηθεί. Τα διαθέσιμα χρονικά διαστήματα του πάροχου θα διασπαστούν ξανά μεταξύ των ραντεβού αυτών και έτσι θα ολοκληρωθεί η διαδικασία του υπολογισμού (γραμμές 84 - 137). Αν την επιλεγμένη ημερομηνία ο πάροχος δεν έχει κανένα ραντεβού τότε δεν πραγματοποιείται καμία επιπλέον διάσπαση και το αποτέλεσμα επιστρέφεται όπως είναι. Στην επόμενη μέθοδο ο πίνακας που περιέχει τα διαστήματα θα χρησιμοποιηθεί για να υπολογιστούν οι ακριβείς διαθέσιμες ώρες στις οποίες θα μπορεί ο πελάτης να κλείσει κάποιο ραντεβού για την επιλεγμένη υπηρεσία.
|
|
||||||
|
|
||||||
\lstinputlisting{snippets/provider_appointment_hours.php}
|
|
||||||
|
|
||||||
Η δεύτερη μέθοδος αποτελεί απάντηση σε κλήση της JavaScript με χρήση της τεχνικής AJAX. Όταν ο client καλεί αυτήν την μέθοδο παρέχει τα στοιχεία του πάροχου, την διάρκεια της επιλεγμένης υπηρεσίας (σε λεπτά) και το αν ο χρήστης επεξεργάζεται το συγκεκριμένο ραντεβού ή όχι (παράμετρος manage\_mode). Αυτό που εκτελείται αρχικά είναι η λήψη των ελεύθερων χρονικών διαστημάτων του πάροχου χρησιμοποιώντας την προαναφερθέντα μέθοδο get\_provider\_available\_time\_periods (γραμμές 28 - 34).
|
|
||||||
|
|
||||||
Έπειτα θα υπολογιστούν οι διαθέσιμες ώρες στις οποίες θα μπορέσει ο πελάτης να κλείσει ραντεβού. Αυθαίρετα και για λόγους ευχρηστίας έχει τεθεί το χρονικό διάστημα μεταξύ των ελεύθερων ωρών να είναι τα 15 λεπτά. Αυτό που κάνει το συγκεκριμένο κομμάτι κώδικα είναι ουσιαστικά ο διαχωρισμός των ελεύθερων χρονικών διαστημάτων του πάροχου σε ώρες τις οποίες χωρίζουν 15 λεπτά τουλάχιστον και οι οποίες μπορούν να χωρέσουν την διάρκεια της υπηρεσίας για την οποία ενδιαφέρεται ο πελάτης, πριν την λήξη του διαθέσιμου χρονικού διαστήματος (γραμμές 41 - 74).
|
|
||||||
|
|
||||||
Στο τελευταίο μέρος αυτής της μεθόδου ελέγχεται αν η επιλεγμένη ημερομηνία αντιστοιχεί στην σημερινή και αν αυτό ισχύει αφαιρούνται οι παρελθοντικές διαθέσιμες ώρες έτσι ώστε να μην μπορεί ο πελάτης να κλείσει ραντεβού σε μια παρελθοντική χρονική στιγμή. Το σύστημα στο frontend δεν επιτρέπει ούτως ή άλλος την επιλογή παρελθοντικής ημερομηνίας, αλλά απαιτείται στην συγκεκριμένη περίπτωση να ελεγχθούν οι παρελθοντικές ώρες του ραντεβού. Επίσης είναι σημαντικό να αναφερθεί ότι η εφαρμογή παρέχει μια παράμετρο η οποία ορίζει το χρονικό διάστημα που θα πρέπει να χωρίζει ένα ραντεβού από την ώρα που αυτό γίνεται κράτηση ή επεξεργάζεται. Ο λόγος γίνεται για την ρύθμιση του συστήματος με το όνομα "book\_advance\_timeout" η οποία μετράται σε λεπτά και λαμβάνεται υπόψιν στον υπολογισμό των διαθέσιμων ωρών.
|
|
||||||
|
|
||||||
%% ==================================================
|
|
||||||
%% ΔΙΑΓΡΑΜΜΑΤΑ ΚΩΔΙΚΑ
|
|
||||||
%% ==================================================
|
|
||||||
\section{Διαγράμματα Κώδικα}
|
|
||||||
Σε αυτήν την ενότητα θα παρατεθούν κάποια διαγράμματα κώδικα τα οποία θα βοηθήσουν τον αναγνώστη στην κατανόηση της λειτουργίας του συστήματος και στον τρόπο με τον οποίο διεκπεραιώνονται οι εργασίες που απαιτούνται στην εκάστοτε περίπτωση χρήσης. Τα διαγράμματα αυτά ακολουθούν το σχεδιαστικό πρότυπο UML το οποίο αποτελεί την πιο δημοφιλής γλώσσα μοντελοποίησης εδώ και αρκετά χρόνια.
|
|
||||||
|
|
||||||
Η εφαρμογή που χρησιμοποιήθηκε για τον σχεδιασμό των διαγραμμάτων αυτών είναι η draw.io και πρόκειται για μια διαδικτυακή πλατφόρμα με την οποία μπορούν να γίνουν σχεδιαγράμματα πολλών διαφορετικών τύπων. Το draw.io είναι δωρεάν προς χρήση και μπορεί να βρεθεί στην διεύθυνση http://www.draw.io.
|
|
||||||
|
|
||||||
\subsection{Διαγράμματα ροής}
|
|
||||||
Τα διαγράμματα ροής δείχνουν τον τρόπο και την σειρά με την οποία λειτουργούν οι διεργασίες και τα αντικείμενα μεταξύ τους για την διεκπεραίωση ενός σκοπού. Σε αυτά είναι εύκολο να διακριθούν ποιοι ηθοποιοί, αντικείμενα, διεπαφές και μέθοδοι αλληλεπιδρούν έτσι ώστε τα δεδομένα που χρειάζονται για την εργασία να παραχθούν επιτυχώς και να φτάσουν ακέραια στον προορισμό τους. Σε αυτά τα διαγράμματα ο χρονικός προσδιορισμός της κάθε αλληλεπίδρασης είναι εμφανής και πολύ σημαντικός για να μπορέσει ο προγραμματιστής να καταλάβει με ποια σειρά θα πρέπει να πορευτεί η εκτέλεση έτσι ώστε αυτός να καταλήξει σε αναμενόμενο αποτέλεσμα. Συνήθως τα διαγράμματα ροής συγχέονται με το σενάριο κάποιας περίπτωσης χρήσης αλλά μπορούν να διασπαστούν και σε μικρότερα τμήματα τα οποία να επικεντρώνουν στα σημεία που είναι πιο σημαντικά.
|
|
||||||
|
|
||||||
\begin{figure}%% [Η] αυτή η εντολή θα τοποθετήσει το διάγραμμα ακριβώς σε αυτό το σημείο. Το latex όμως πάντα προσπαθεί να αφήσει όσο λιγότερα κενό χόρο γίνεται και έτσι τα διαγράμματα δεν θα εμφανιστούν με την σειρά που γράφονται στον κώδικα.
|
|
||||||
\centering
|
|
||||||
\includegraphics[width=150mm]{images/sd-save-appointment.png}
|
|
||||||
\caption{Διάγραμμα ροής για την διαδικασία αποθήκευσης ενός ραντεβού.}
|
|
||||||
\label{sd-save-appointment}
|
|
||||||
\end{figure}
|
|
||||||
|
|
||||||
\begin{figure}
|
|
||||||
\centering
|
|
||||||
\includegraphics[width=150mm]{images/sd-sync-appointment.png}
|
|
||||||
\caption{Διάγραμμα ροής για την διαδικασία προσθήκης ενός ραντεβού στο Google Calendar.}
|
|
||||||
\label{sd-save-appointment}
|
|
||||||
\end{figure}
|
|
||||||
|
|
||||||
\subsection{Διαγράμματα δραστηριότητας}
|
|
||||||
Τα διαγράμματα δραστηριότητας αποτελούν γραφικές παρουσιάσεις της δραστηριότητας του που ακολουθεί το σύστημα ανάλογα με τις αποφάσεις που λαμβάνονται μέσα από τον κώδικα. Σε αυτά τα διαγράμματα μπορούν να φανούν τα σημεία στα οποία υπάρχουν βρόγχοι επανάληψης, τα σημεία όπου παίρνονται αποφάσεις όπως και επίσης τις διαδικασίες που τρέχουν ταυτόχρονα και σε ποιο σημείο χρονικά γίνεται αυτό. Κατά κύριο λόγο τα διαγράμματα δραστηριότητας δείχνει την συνολική ροή του ελέγχου μέσα από την εκτέλεση μιας συγκεκριμένης διαδικασίας.
|
|
||||||
|
|
||||||
\begin{figure}
|
|
||||||
\centering
|
|
||||||
\includegraphics[width=90mm]{images/ad-book-appointment.png}
|
|
||||||
\caption{Διάγραμμα δραστηριότητας της διαδικασίας κράτησης ραντεβού.}
|
|
||||||
\label{ad-book-appointment}
|
|
||||||
\end{figure}
|
|
||||||
|
|
||||||
\begin{figure}
|
|
||||||
\centering
|
|
||||||
\includegraphics[width=70mm]{images/ad-install-application.png}
|
|
||||||
\caption{Διάγραμμα δραστηριότητας της διαδικασίας εγκατάστασης της εφαρμογής.}
|
|
||||||
\label{ad-install-application}
|
|
||||||
\end{figure}
|
|
||||||
|
|
||||||
\begin{figure}
|
|
||||||
\centering
|
|
||||||
\includegraphics[width=70mm]{images/ad-sync-appointments.png}
|
|
||||||
\caption{Διάγραμμα δραστηριότητας της διαδικασίας αμφίδρομου συγχρονισμού με το Google Calendar.}
|
|
||||||
\label{ad-sync-appointments}
|
|
||||||
\end{figure}
|
|
||||||
|
|
||||||
\begin{figure}
|
|
||||||
\centering
|
|
||||||
\includegraphics[width=70mm]{images/ad-provider-available-hours.png}
|
|
||||||
\caption{Διάγραμμα δραστηριότητας του υπολογισμού των διαθέσιμων ωρών ενός πάροχου.}
|
|
||||||
\label{ad-provider-available-hours}
|
|
||||||
\end{figure}
|
|
||||||
|
|
||||||
\subsection{Διαγράμματα κλάσεων}
|
|
||||||
Στην τεχνολογία λογισμικού, τα διαγράμματα κλάσεων περιγράφουν την στατική δομή ενός συστήματος δείχνοντας τις κλάσεις, τις ιδιότητες, τις λειτουργίες και τις σχέσεις μεταξύ των αντικειμένων. Τα σχεδιαγράμματα αυτά είναι τα βασικότερα για έναν προγραμματιστή διότι μπορεί άμεσα να πληροφορηθεί σχετικά με την δομή του κώδικα και με ποιόν τρόπο θα πρέπει να συνεχιστεί η διαδικασία της υλοποίησης. Επίσης είναι εμφανές και οι αρχιτεκτονικές επιλογές που έχουν γίνει καθώς κάθε σχεδιαστικό πρότυπο που πρέπει να έχει ο κώδικας μπορεί να διακριθεί και να περιγραφή σε αυτά τα διαγράμματα. Καλή πρακτική είναι πάντα ένα διάγραμμα να περιέχει μόνο την ουσία οπότε στο υποκεφάλαιο αυτό εμφανίζονται διαγράμματα κλάσης τα οποία δείχνουν κάποιες σχεδιαστικές επιλογές που έχουν γίνει στην εφαρμογή.
|
|
||||||
|
|
||||||
\begin{figure}
|
|
||||||
\centering
|
|
||||||
\includegraphics[width=150mm]{images/cd-backend-users.png}
|
|
||||||
\caption{Διάγραμμα κλάσεων της δομής JavaScript στην σελίδα διαχείρισης των χρηστών.}
|
|
||||||
\label{cd-backend-users}
|
|
||||||
\end{figure}
|
|
||||||
|
|
||||||
\begin{figure}
|
|
||||||
\centering
|
|
||||||
\includegraphics[width=150mm]{images/cd-backend-settings.png}
|
|
||||||
\caption{Διάγραμμα κλάσεων της δομής JavaScript στην σελίδα ρυθμίσεων της εφαρμογής.}
|
|
||||||
\label{cd-backend-settings}
|
|
||||||
\end{figure}
|
|
|
@ -1,144 +0,0 @@
|
||||||
%% ΕΙΣΑΓΩΓΙΚΟ ΚΕΦΑΛΑΙΟ
|
|
||||||
%% Το μέρος του εγγράφου αυτού περιέχει τα πρώτα μέρη της διπλωματικής
|
|
||||||
%% (πρωτοσέλιδο, περιεχόμενα, πρόλογος κτλ) καθώς και ένα κεφάλαιο που
|
|
||||||
%% αναλύει και περιγράφει το πρόβλημα που επιλύει το σύστημα που αναπτήχθηκε.
|
|
||||||
|
|
||||||
\Titlepage
|
|
||||||
\Declarationpage
|
|
||||||
|
|
||||||
\begin{Abstract}
|
|
||||||
Η εργασία αυτή πραγματεύεται την υλοποίηση ενός διαδικτυακού συστήματος κρατήσεων ραντεβού για επιχειρήσεις με πλήρη περιβάλλον διαχείρισης και την δυνατότητα συγχρονισμού των ραντεβού με το Google Calendar API. Στόχος είναι να κατασκευαστεί ένα ευέλικτο σύστημα το οποίο να είναι σε θέση να εξυπηρετήσει τις ανάγκες οποιασδήποτε επιχείρησης βελτιώνοντας έτσι την μηχανογράφηση, την οργάνωση και κατ' επέκταση την απόδοση της. Όλα αυτά σαφώς συντελούν στην μείωση του κόστους λειτουργίας, κάτι το οποίο είναι πολύ σημαντικό. Για την υλοποίηση της εφαρμογής επιλέχθηκε η γλώσσα προγραμματισμού PHP και JavaScript καθώς και κάποιες εξωτερικές βιβλιοθήκες κώδικα, οι οποίες φάνηκαν πολύ χρήσιμες.
|
|
||||||
\end{Abstract}
|
|
||||||
|
|
||||||
\tableofcontents
|
|
||||||
\listoffigures
|
|
||||||
|
|
||||||
\begin{Definitions}
|
|
||||||
Στο έγγραφο αυτό υπάρχουν κάποιες έννοιες οι οποίες χρησιμοποιούνται
|
|
||||||
σε διάφορα σημεία. Παρακάτω παρατίθενται οι περιγραφές τους.
|
|
||||||
\begin{description}
|
|
||||||
\item [Easy!Appointments] Με την ονομασία Easy!Appointments θα γίνεται αναφορά στο σύστημα που υλοποιήθηκε.
|
|
||||||
|
|
||||||
\item [Διαχειριστής] Ο διαχειριστής του συστήματος είναι ο χρήστης ο οποίος έχει όλα τα δικαιώματα αλλαγών και ρυθμίσεων του Easy!Appointments. Μπορεί να ορίσει νέες υπηρεσίες και πάροχους υπηρεσίας, να ρυθμίσει το σύστημα ειδοποιήσεων και να εκτελέσει όλες τις δυνατές διαδικασίες διαχείρισης των δεδομένων.
|
|
||||||
|
|
||||||
\item [Πάροχος Υπηρεσίας] Ο πάροχος υπηρεσίας είναι η οντότητα που εξυπηρετεί μια ή περισσότερες υπηρεσίες. Μπορεί να αντιπροσωπεύει ένα άτομο ή μια ομάδα ατόμων. Σε κάθε περίπτωση όμως διαχειρίζεται από έναν χρήστη του συστήματος.
|
|
||||||
|
|
||||||
\item [Πελάτης] Ο πελάτης αφού δει τις διαθέσιμες ημερομηνίες και ώρες για τις επιλεγμένες υπηρεσίες και παρόχους, μπορεί να κλείνει ραντεβού με την επιχείρηση. Αν γίνει οποιαδήποτε αλλαγή σε κάποιο ραντεβού του πελάτη τότε αυτός θα ενημερωθεί με σχετικό email.
|
|
||||||
|
|
||||||
\item [Γραμματέας] Ο γραμματέας είναι ένας χρήστης ο οποίος μπορεί να διαχειριστεί τα ραντεβού και τους πελάτες του συστήματος για συγκεκριμένους πάροχους υπηρεσιών. Το σε ποιους πάροχους αντιστοιχεί ο κάθε χρήστης γραμματέας ορίζεται από τον διαχειριστή στο περιβάλλον ρυθμίσεων της εφαρμογής.
|
|
||||||
|
|
||||||
\item [Πλάνο Πάροχου] Από την στιγμή που κλείνονται ραντεβού σε έναν πάροχο υπηρεσιών το ημερολογιακό του πλάνο αρχίζει να γεμίζει από χρονικά διαστήματα, τα οποία είναι δεσμευμένα και αντιπροσωπεύουν συναντήσεις με τους πελάτες. Εκτός αυτού υπάρχει και η δυνατότητα να τεθεί ένα ανενεργό χρονικό διάστημα, στο οποίο ο συγκεκριμένος πάροχος δεν θα είναι διαθέσιμος έτσι ώστε να μην μπορούν οι πελάτες να κλείνουν ραντεβού σε αυτό το διάστημα. Αυτό το πλάνο μπορεί να συγχρονιστεί με το Google Calendar έτσι ώστε να είναι προσβάσιμο και από άλλες υπηρεσίες.
|
|
||||||
|
|
||||||
\end{description}
|
|
||||||
\end{Definitions}
|
|
||||||
|
|
||||||
%% =============================================
|
|
||||||
%% ΚΕΦΑΛΑΙΟ 1 - ΕΙΣΑΓΩΓΗ
|
|
||||||
%% =============================================
|
|
||||||
\chapter{Εισαγωγή}
|
|
||||||
\leftmark\rightmark
|
|
||||||
Το παρόν κεφάλαιο επεξηγεί τον σκοπό ανάπτυξης του Easy!Appointments καθώς και τις ανάγκες που καλύπτει σε μια επιχείρηση. Επιπρόσθετα αναφέρονται παρόμοια συστήματα και οι διαφορές που έχουν σε σχέση με την εφαρμογή που υλοποιήθηκε.
|
|
||||||
|
|
||||||
\section {Ποια προβλήματα προσπαθεί να λύσει η εφαρμογή}
|
|
||||||
Οι επιχειρήσεις από την φύση τους χρειάζεται να έρχονται σε επαφή με τους πελάτες για να μπορέσουν να τους εξυπηρετήσουν και έτσι να λάβουν την αμοιβή τους. Ανάλογα με την μορφή και το είδος της επιχείρησης η επαφή αυτή διαφέρει. Για παράδειγμα κάποιες επιχειρήσεις έρχονται σε επαφή με περισσότερους πελάτες, άλλες με λιγότερους αλλά η εξυπηρέτηση είναι παθητική (πχ κατάστημα ηλεκτρονικών ειδών) και κάποιες απαιτούν ιδιαίτερη προσοχή στον πελάτη καθώς η εξυπηρέτησή του μπορεί να γίνει μόνο προσωπικώς, από κάποιον υπάλληλο ή επαγγελματία (πάροχος της υπηρεσίας). Η τελευταία κατηγορία περιέχει ένα μεγάλο εύρος επιχειρήσεων το οποίο για να οργανώσει και να διευκολύνει το πελατειακό κοινό του λειτουργεί κανονίζοντας ραντεβού με τους ενδιαφερόμενους πελάτες.
|
|
||||||
|
|
||||||
Η κράτηση ενός ραντεβού είναι μια διαδικασία η οποία γίνεται συνήθως τηλεφωνικώς, είτε μετά από προσωπικό κανονισμό με κάποιον αρμόδιο. Η διαδικασία αυτή αποτελείται τις περισσότερες φορές από τα παρακάτω μέρη:
|
|
||||||
\begin{enumerate}
|
|
||||||
\item Ο ενδιαφερόμενος πελάτης έρχεται σε επαφή με την επιχείρηση και ζητάει να κάνει κράτηση την επιθυμητή ημερομηνία και ώρα, για μια συγκεκριμένη υπηρεσία.
|
|
||||||
\item Ο αρμόδιος υπάλληλος ψάχνει σε κάποιο ημερολόγιο ή αρχείο υπολογιστή τα ραντεβού για την συγκεκριμένη ημερομηνία και ανάλογα με την διαθεσιμότητα ανταποκρίνεται στον πελάτη.
|
|
||||||
\item Αν η συγκεκριμένη χρονική στιγμή δεν είναι διαθέσιμη θα χρειαστεί να γίνει μια αντιπρόταση από τον υπάλληλο ή ο πελάτης να βρει κάποια άλλη στιγμή που θα είναι αυτός διαθέσιμος.
|
|
||||||
\end{enumerate}
|
|
||||||
Αν παρατηρήσουμε όμως την παραπάνω διαδικασία, θα δούμε πως έχει κάποια σημαντικά μειονεκτήματα, τα οποία μάλιστα συνεπάγονται την αύξηση του κόστους λειτουργίας μιας επιχείρησης και την μείωση της ποιότητας εξυπηρέτησης των πελατών.
|
|
||||||
|
|
||||||
Η ίδια η διαδικασία της κράτησης ενός ραντεβού με τον συγκεκριμένο τρόπο απαιτεί από μόνη της την ύπαρξη ενός υπαλλήλου, ο οποίος θα αφιερώνει αρκετό, αν όχι τον περισσότερο από τον χρόνο του για να κάνει αυτήν την εργασία. Αυτό πρακτικά σημαίνει δέσμευση ανθρώπινων πόρων της επιχείρησης και συνεπάγεται στην αύξηση των εξόδων λειτουργίας.
|
|
||||||
|
|
||||||
Επιπλέον η ίδια η διαδικασία μπορεί να είναι χρονοβόρα και κουραστική για τους πελάτες, ειδικά στις περιπτώσεις όπου υπάρχει λίγο προσωπικό για να καλύψει μεγάλο κοινό (πχ νοσοκομεία). Στις περιπτώσεις αυτές οι πελάτες περιμένουν στην αναμονή για μεγάλο χρονικό διάστημα και μάλιστα πολλές φορές δεν πιάνουν γραμμή για να μπορέσουν να κρατήσουν κάποιο ραντεβού. Επίσης πρέπει να σημειωθεί ότι όταν ο πελάτης καταφέρει να κλείσει το ραντεβού του συνήθως δεν έχει επιλογή για το πότε θα γίνει και απλώς ενημερώνεται για την ημερομηνία την οποία έχει ορίσει το προσωπικό, ανάλογα με τις εκάστοτε συνθήκες.
|
|
||||||
|
|
||||||
Εκτός αυτών η εκτέλεση αυτής της διαδικασίας είναι αρκετά επιρρεπής στο να έχει ασαφές αποτελέσματα με την έννοια του ότι δεν υπάρχει κάποιο κοινό σημείο αναφοράς για την συμφωνία που πραγματοποιείται μεταξύ της επιχείρησης και του πελάτη, έτσι ώστε να μπορεί να γίνει εξακρίβωση και επαλήθευση των ιδιοτήτων μιας κράτησης και από τις δύο πλευρές. Αυτό μπορεί να οδηγήσει σε προβλήματα με τους πελάτες, κάτι το οποίο δεν είναι επιθυμητό σε καμία περίπτωση.
|
|
||||||
|
|
||||||
Μικρό είναι το μέρος των πληροφοριών που καταγράφεται με το πέρας της κράτησης, καθώς τα μέσα που χρησιμοποιούνται δεν επιτρέπουν ή κάνουν δύσκολη και χρονοβόρα την αποθήκευση όλων των δεδομένων. Αυτό συντελεί στην πρόσθετη μείωση της ποιότητας εξυπηρέτησης και της απόδοσης της επιχείρησης.
|
|
||||||
|
|
||||||
Τα δεδομένα αυτά διαχειρίζονται συνήθως δύσκολα. Ακόμα και στην περίπτωση που χρησιμοποιούνται ηλεκτρονικά μέσα για την αποθήκευση των κρατήσεων η τροποποίηση ή ο έλεγχος μπορούν να είναι δύσκολες και χρονοβόρες διαδικασίες, οι οποίες εξαρτώνται κάθε φορά από το επίπεδο της οργάνωσης της επιχείρησης και τις τεχνολογίες που χρησιμοποιούνται.
|
|
||||||
|
|
||||||
Επίσης τα δεδομένα αυτά δεν είναι προσβάσιμα από οποιονδήποτε ανά πάσα στιγμή, αλλά μόνο στον χώρο της επιχείρησης και μόνο από το άτομο το οποίο διαχειρίζεται τα ραντεβού.
|
|
||||||
|
|
||||||
Τα παραπάνω προβλήματα διογκώνονται σημαντικά όταν πρόκειται για μεγάλες επιχειρήσεις και οργανισμούς οι οποίοι εξυπηρετούν μεγάλο αριθμό πελατών.
|
|
||||||
|
|
||||||
\section {Γιατί είναι σημαντικά τα προβλήματα αυτά}
|
|
||||||
Οι απαιτήσεις και η ανταγωνιστικότητα που υπάρχει μεταξύ των επιχειρήσεων αυτήν την εποχή απαιτεί την γρήγορη και άμεση διεκπεραίωση διεργασιών και την όσο το δυνατόν καλύτερη οργάνωση τους, για να μπορούν να παρέχουν υπηρεσίες υψηλού επιπέδου με το χαμηλότερο δυνατό κόστος και προσωπικό. Για να επιτύχουν τον σκοπό αυτό οι επιχειρήσεις πρέπει να επιλέξουν τα κατάλληλα εργαλεία οργάνωσης και εξυπηρέτησης των πελατών τους.
|
|
||||||
|
|
||||||
Βλέποντας τα προβλήματα που αναφέρθηκαν προηγουμένως είναι κατανοητό ότι με την χρήση της έως τώρα μεθόδου κράτησης ραντεβού επέρχεται μείωση της ποιότητας και της απόδοσης της επιχείρησης. Αυτό σημαίνει ότι το επίπεδο εξυπηρέτησης είναι χαμηλότερο και έτσι η επιχείρηση αδυνατεί να είναι ανταγωνιστική προς τις άλλες καθώς γίνεται σπατάλη πόρων για την υλοποίηση αυτής της διαδικασίας.
|
|
||||||
|
|
||||||
Η μείωση αυτή επιφέρει αύξηση του κόστους λειτουργίας το οποίο αποτελεί ένα επιπρόσθετο εμπόδιο στην προσπάθεια για ανάπτυξη και επέκταση. Πολλές φορές μάλιστα αυτή η αύξηση του κόστους σε συνδυασμό με άλλους παράγοντες μπορεί να συντελέσουν στην μη βιωσιμότητα και το κλείσιμο της επιχείρησης, εφόσον αυτή δεν μπορεί να παράγει κέρδη.
|
|
||||||
|
|
||||||
Παρατηρείται λοιπόν ότι η σημερινή οργάνωση των επιχειρήσεων που λειτουργούν με ραντεβού θα μπορούσε να βελτιωθεί με την χρήση ενός ηλεκτρονικού συστήματος που θα επίλυε τα προαναφερθέντα προβλήματα και θα πρόσδιδε μεγαλύτερη ευκολία στην εξυπηρέτηση του κοινού. Η προτεινόμενη λύση αποσκοπεί στο να εκπληρώσει αυτά τα κενά και να εντάξει στο ενεργητικό της επιχείρησης ένα δυνατό εργαλείο οργάνωσης.
|
|
||||||
|
|
||||||
\section{Παρόμοιες λύσεις που υπάρχουν ήδη}
|
|
||||||
Όπως είναι φυσικό για ένα τέτοιο μείζων ζήτημα υπάρχουν ήδη αρκετές εφαρμογές που αναλαμβάνουν την μηχανογράφηση των ραντεβού μιας επιχείρησης. Όλες οι εφαρμογές είναι διαδικτυακές και σε μερικές περιπτώσεις συναντάται η διάθεση τους και για κινητές συσκευές. Οι εταιρείες κάνουν προσπάθειες στο να καταστήσουν τα λογισμικά τους εύκολα στην χρήση παρέχοντας αρκετές λειτουργίες επικοινωνίας με άλλα δημοφιλή συστήματα όπως για παράδειγμα το Outlook, το iCal και το Google Calendar. Παρακάτω περιγράφονται κάποια από αυτά τα συστήματα.
|
|
||||||
|
|
||||||
\subsection{Genbook}
|
|
||||||
Το Genbook είναι μια online υπηρεσία που προσφέρει στις επιχειρήσεις την δυνατότητα να εγγραφούν (πληρώνοντας το αντίτιμο) και να χρησιμοποιήσουν την εφαρμογή που τους επιτρέπει να διαχειρίζονται τα ραντεβού. Παρέχει αρκετά φιλικό περιβάλλον, είναι παραμετροποιήσιμο και περιέχει την δυνατότητα παραγωγής στατιστικών στοιχείων για τις υπηρεσίες που είναι διαθέσιμες προς το κοινό.
|
|
||||||
|
|
||||||
Αυτό που δεν υποστηρίζει είναι η δημιουργία πολλαπλών πλάνων που να αντιπροσωπεύουν διαφορετικούς τομείς ή υπαλλήλους (όλα τα ραντεβού φαίνονται σε ένα ημερολόγιο).
|
|
||||||
|
|
||||||
Παρατηρήσεις: επί πληρωμή, ικανοποιητικά παραμετροποιήσιμο, δημιουργία στατιστικών
|
|
||||||
|
|
||||||
\href{http://www.genbook.com}{www.genbook.com}
|
|
||||||
|
|
||||||
\subsection{Web Appointment Scheduling System (Open Source)}
|
|
||||||
Το WASS είναι μια λύση ανοιχτού κώδικα η οποία περιέχει τις βασικότερες λειτουργίες διαχείρισης ραντεβού για μια επιχείρηση. Από την εφαρμογή αυτή λείπουν κάποια στοιχεία διαχείρισης και παραμετροποίησης και το γραφικό περιβάλλον του χρήστη χρειάζεται επιπλέον δουλειά. Παρ' όλα αυτά είναι δωρεάν και προτείνεται για οποιαδήποτε μικρή επιχείρηση. Η εφαρμογή υποστηρίζει το iCal της Apple και την δημιουργία πολλών πλάνων.
|
|
||||||
|
|
||||||
Παρατηρήσεις: δωρεάν, βασικές λειτουργίες, ανοιχτός κώδικας, υποστήριξη iCal
|
|
||||||
|
|
||||||
\href{https://wass.princeton.edu/pages/login.page.php}{www.wass.princeton.edu} |
|
|
||||||
\href{http://sourceforge.net/projects/wass/}{www.sourceforge.net}
|
|
||||||
|
|
||||||
\subsection{Appointment-Plus}
|
|
||||||
Το Appointment-plus είναι από τις πιο οργανωμένες και εμπλουτισμένες εφαρμογές που υπάρχουν σε αυτόν τον τομέα. Έχει εκδόσεις για οποιαδήποτε συσκευή (pc, tablets, smartphones), όμορφο περιβάλλον, υποστήριξη συγχρονισμού δεδομένων με άλλες υπηρεσίες και εφαρμογές (Google, Outlook, iCal κτλ), χρήση από πολλούς υπαλλήλους και πολλά πλάνα. Παρέχει λειτουργία αναμονής για τους πελάτες σε περίπτωση που η επιθυμητή ώρα είναι πιασμένη. Υπάρχει σύστημα email στο οποίο ο πελάτης μπορεί να κάνει επιλογές και να τις αποστείλει πίσω στο σύστημα. Δυνατότητα για τροποποίηση της σελίδας που βλέπει ο χρήστης και πώλησης προϊόντων μέσω της εφαρμογής. Η εταιρεία προσφέρει σε κάθε πελάτη έναν βοηθό στον οποίο θα μπορεί να απευθυνθεί για να ρυθμίσει την εφαρμογή.
|
|
||||||
|
|
||||||
Παρατηρήσεις: επί πληρωμή, πλήρως παραμετροποιήσιμο, λειτουργία σε διαφορετικές συσκευές, πολλαπλά πλάνα, υποστήριξη (τηλέφωνο - email), το χρησιμοποιούν μεγάλες εταιρείες, οργανισμοί και πανεπιστημιακά ιδρύματα
|
|
||||||
|
|
||||||
\href{http://www.appointment-plus.com/}{www.appointment-plus.com}
|
|
||||||
|
|
||||||
\subsection{Acuity Scheduling}
|
|
||||||
Η εφαρμογή αυτή αν και πιο απλή από την Appointment-plus περιέχει όλες τις βασικές λειτουργίες που θα χρειαστεί μια επιχείρηση για την υλοποίηση ενός συστήματος ραντεβού. Υποστηρίζει την δυνατότητα τροποποίησης της εμφάνισης, δημιουργία πολλών υπαλλήλων και πλάνων, ηλεκτρονικών πληρωμών με πιστωτική κάρτα, εξαγωγή ημερολογίου σε άλλες εφαρμογές (Facebook, Google και Outlook), ιστορικό, διαχείριση πελατών και λειτουργία σε iPhone. Επίσης δίνει την δυνατότητα πώλησης προϊόντων (eshop) για ηλεκτρονικές αγορές.
|
|
||||||
|
|
||||||
Παρατηρήσεις: επί πληρωμή (δωρεάν για έναν χρήστη αλλά με περιορισμούς), υποστήριξη προϊόντων, iPhone, εξαγωγή σε Google, Outlook και Facebook
|
|
||||||
|
|
||||||
\href{http://www.acuityscheduling.com/}{www.acuityscheduling.com}
|
|
||||||
|
|
||||||
\subsection{SetMore}
|
|
||||||
Το SetMore έχει απλή και όμορφη εμφάνιση και παρέχει ένα πλήρως παραμετροποιήσιμο περιβάλλον. Είναι το μόνο που υποστηρίζει SMS ειδοποιήσεις και αυτό σε beta στάδιο. Η διαδικασία κράτησης ενός ραντεβού χωρίζεται όπως και με τα υπόλοιπα συστήματα, σε έναν οδηγό με 4-5 βήματα στα οποία ο χρήστης επιλέγει σε ποια υπηρεσία και σε ποιόν υπάλληλο θέλει να κλείσει ραντεβού. Είναι πολύ εύκολο στην χρήση και υποστηρίζει plugins για το WordPress και το Facebook.
|
|
||||||
|
|
||||||
Παρατηρήσεις: επί πληρωμή, υποστήριξη SMS, λειτουργία με WordPress και Facebook, δεν μπορεί να εξάγει τα δεδομένα του σε άλλη εφαρμογή (Google Calendar, Outlook)
|
|
||||||
|
|
||||||
\href{http://www.setmore.com/}{www.setmore.com}
|
|
||||||
|
|
||||||
\subsection{Υπόλοιπα συστήματα}
|
|
||||||
Εκτός των αναφερθέντων υπάρχουν πολλές άλλες εφαρμογές διαθέσιμες προς το κοινό. Μερικές από αυτές αναφέρονται στην παρακάτω λίστα:
|
|
||||||
\begin{enumerate}
|
|
||||||
\item SnapAppointments
|
|
||||||
\item Doodle
|
|
||||||
\item Bookeo
|
|
||||||
\item ScheduleOnce
|
|
||||||
\item BookingBug
|
|
||||||
\item SetSter
|
|
||||||
\item Agreedo
|
|
||||||
\item BookedIn
|
|
||||||
\item Book'd
|
|
||||||
\item Schedulista
|
|
||||||
\end{enumerate}
|
|
||||||
|
|
||||||
\section{Σε τι διαφέρει από τις υπόλοιπες η προτεινόμενη λύση}
|
|
||||||
Το Easy!Appointments έχει ως σκοπό να αυτοματοποιήσει την διαδικασία της κράτησης και διαχείρισης ραντεβού για οποιαδήποτε επιχείρηση. Χρησιμοποιώντας τις δυνατότητες που μας παρέχει το διαδίκτυο μπορεί να υλοποιηθεί ένα σύστημα το οποίο να έχει την δυνατότητα να οργανώσει τα επαγγελματικά πλάνα πολλών υπαλλήλων ταυτόχρονα, επιφέροντας έτσι όχι μόνο την μείωση του χρόνου που απαιτούσαν οι παλιές μέθοδοι διαχείρισης ραντεβού, αλλά και την αύξηση της παραγωγικότητας της επιχείρησης. Οι πελάτες δεν θα χρειάζεται πλέον να τηλεφωνούν ή να πηγαίνουν στο κατάστημα αλλά θα μπορούν να βλέπουν τις διαθέσιμες ώρες της επιχείρησης και να κλείνουν το ραντεβού τους την επιθυμητή ημερομηνία και ώρα μέσω του υπολογιστή και του internet. Αυτό έχει ως αποτέλεσμα την ποιοτικότερη αλλά και αποδοτικότερη εξυπηρέτηση τους. Επιπρόσθετα βελτιώνεται η επικοινωνία και η οργάνωση των συντελεστών της επιχείρησης, παρέχοντας δυνατότητες αρχειοθέτησης και διαχείρισης των δεδομένων που αποθηκεύονται στο σύστημα ανά πάσα στιγμή και σε οποιοδήποτε μέρος. Σε αντίθεση με τα άλλα συστήματα, προσφέρει επιπλέον τα εξής:
|
|
||||||
|
|
||||||
\begin{enumerate}
|
|
||||||
\item {\bf Αυτόνομη Εγκατάσταση:} Η επιχείρηση που θέλει να χρησιμοποιήσει την εφαρμογή θα μπορεί να την εγκαταστήσει στον server της και να την τρέξει μαζί με κάποιο άλλο site, έχοντας έτσι πλήρη πρόσβαση στα δεδομένα και τον κώδικα. Η διαδικασία της εγκατάστασης και παραμετροποίησης είναι παρόμοια με άλλα συστήματα (Joomla, WordPress κτλ) και όσο πιο αυτοματοποιημένη γίνεται.
|
|
||||||
|
|
||||||
\item {\bf Διαμόρφωση Πλάνου Πάροχου:} Το σύστημα θα έχει ενσωματωμένη δυνατότητα δημιουργίας ημερολογιακού πλάνου εργασίας για τον κάθε πάροχο υπηρεσιών. Το πλάνο αυτό θα αποτελεί την βάση της κάθε εβδομάδας και από εκεί και πέρα ο διαχειριστής θα μπορεί να πραγματοποιήσει αλλαγές ανάλογα με τις εκάστοτε ανάγκες.
|
|
||||||
|
|
||||||
\item {\bf Υποστήριξη Γραμματείας:} Αν παρόλα αυτά η εταιρεία ορίσει κάποια γραμματέα ως υπεύθυνη των ραντεβού, τότε είναι απαραίτητο να μπορεί να διαχειρίζεται μόνο τις εγγραφές που αντιστοιχούν στους πάροχους που βρίσκονται στην αρμοδιότητα της καθώς και τους πελάτες που είναι καταχωρημένοι στο σύστημα. Το Easy!Appointments υποστηρίζει την δημιουργία χρηστών που αντιπροσωπεύουν αυτόν τον σκοπό.
|
|
||||||
|
|
||||||
\item {\bf Αμφίδρομος Συγχρονισμός με το Google Calendar:} Το σύστημα υποστηρίζει τον αμφίδρομο συγχρονισμό ραντεβού με το Google Calendar κάνοντας χρήση του Google Calendar API. Με αυτόν τον τρόπο η διαχείριση των ραντεβού μπορεί να γίνει ακόμα πιο εύκολη, λαμβάνοντας υπόψιν το πόσο δημοφιλής είναι η συγκεκριμένη υπηρεσία της Google.
|
|
||||||
\end{enumerate}
|
|
||||||
|
|
|
@ -1,47 +0,0 @@
|
||||||
%% ΕΛΕΓΧΟΣ ΣΥΣΤΗΜΑΤΟΣ
|
|
||||||
%% Το μέρος του εγγράφου αυτού περιέχει την περιγραφή της διαδικασίας
|
|
||||||
%% ελέγχου που χρησιμοποιείθηκε για την διασφάλιση της σωστής λειτουργίας
|
|
||||||
%% της εφαρμογής.
|
|
||||||
|
|
||||||
\chapter{Έλεγχος Συστήματος}
|
|
||||||
Σε κάθε τομέα παραγωγής προϊόντων είναι πολύ σημαντικό να παράγονται προϊόντα τα οποία να τηρούν πάντα τις προδιαγραφές τους και να μπορούν να αντεπεξέλθουν στις απαιτήσεις του καταναλωτικού κοινού. Η φήμη και η εμπιστοσύνη που προσδίδει μια εταιρεία είναι κομβικά χαρακτηριστικά για την βιωσιμότητας της. Κάθε επαγγελματίας είναι απαραίτητο να είναι σε θέση να εγγυηθεί για την ποιότητα του προϊόντος ή της υπηρεσίας που παρέχει ως αντάλλαγμα της αμοιβής του.
|
|
||||||
|
|
||||||
Ο τρόπος διασφάλισης της ποιότητας διαφέρει ανάλογα με την φύση του προϊόντος ή της υπηρεσίας και μπορεί να εκτελεστεί με διάφορους μεθόδους. Για παράδειγμα αν το προϊόν ήταν κάποιο τρόφιμο η εταιρία θα έπρεπε να είναι σίγουρη ότι είναι σε άριστη κατάσταση πριν φτάσει στο τραπέζι του καταναλωτή, διότι αν δεν το έκανε αυτό θα υπήρχαν επιπλοκές στην υγεία των καταναλωτών. Αντίστοιχα μια εταιρία που παρέχει μια υπηρεσία πρέπει να διασφαλίσει και να ελέγξει την ποιότητα παροχής της υπηρεσίας με διάφορους τρόπους. Ένας από αυτούς θα ήταν να λαμβάνει τις παρατηρήσεις των καταναλωτών αφότου λάβουν την υπηρεσία ή να περνάει από εσωτερικές εξετάσεις και εκπαίδευση τους υπαλλήλους της έτσι ώστε να είναι σίγουρη ότι αυτοί θα μπορούν να παρέχουν σωστά και αξιόπιστα την υπηρεσία στους πελάτες.
|
|
||||||
|
|
||||||
Στην διαδικασία ανάπτυξης λογισμικού υπάρχουν αντίστοιχα διάφοροι τρόποι ελέγχου ότι το λογισμικό που αναπτύσσεται τηρεί τις προδιαγραφές του. Κάποιοι από αυτούς τους τρόπους είναι τα unit testing, fuzz testing, δημοσίευση δοκιμαστική έκδοσης (beta version) κ.α. Το πιο κοντινό εργαλείο ελέγχου στον προγραμματιστή είναι η διαδικασία unit testing η οποία εφαρμόζεται αποκλειστικά σε αντικειμενοστραφή κώδικα. Παρακάτω θα γίνει μια ανάλυση αυτής της τεχνικής ελέγχου και θα αναφερθούν οι μέθοδοι και η διαδικασία ελέγχου πάνω στο Easy!Appointments.
|
|
||||||
|
|
||||||
\section {Unit testing}
|
|
||||||
Για την υλοποίηση unit tests πάνω στον κώδικα είναι απαραίτητο να τηρούνται δύο πράγματα: (1) η αντικειμενοστραφείς δομή και (2) η χρήση κάποιας βιβλιοθήκης ή εργαλείου το οποίο μπορεί να βοηθήσει στην οργάνωση και καλύτερη υλοποίηση των tests.
|
|
||||||
|
|
||||||
Με τον όρο unit testing εννοείται η δοκιμή μίας “λειτουργικής μονάδας” του λογισμικού που αναπτύσσεται. Η κάθε λειτουργική μονάδα απομονώνεται από τις υπόλοιπες και δοκιμάζεται ξεχωριστά σε διάφορες καταστάσεις. Για αυτόν τον λόγο είναι απαραίτητο ο κώδικας να έχει αντικειμενοστραφής δομή. Η διαδικασία χωρίζεται στην συγγραφή πολλαπλών unit test, συναρτήσεων δηλαδή που δοκιμάζουν μια διαδικασία για συγκεκριμένες τιμές εισόδου. Σε κάθε περίπτωση στόχος είναι να υπάρχει ελεγχόμενη έξοδος έτσι ώστε να μπορέσει ο προγραμματιστής να είναι σίγουρος ότι το σύστημα θα λειτουργήσει σωστά σε οποιαδήποτε κατάσταση και αν βρίσκεται. Κατά την διαδικασία αυτήν μπορούν να βρεθούν πολύ εύκολα πολλά προβλήματα και ασυνέπειες στον κώδικα ενός συστήματος, τα οποία χρειάζεται να αντιμετωπιστούν.
|
|
||||||
|
|
||||||
Για να μπορέσουν να υλοποιηθούν αυτά τα test είναι απαραίτητο να χρησιμοποιηθεί κάποια βιβλιοθήκη ή εργαλείο το οποίο θα κατέχει τις βασικές συναρτήσεις ελέγχου αποτελεσμάτων και επιπρόσθετα λειτουργίες για την παραγωγή αναφορών, οι οποίες περιέχουν τα αποτελέσματα των δοκιμών. Υπάρχουν πάρα πολλά εργαλεία που κάνουν αυτήν την δουλειά, το καθένα για μια συγκεκριμένη γλώσσα προγραμματισμού. Τα πιο διαδεδομένα εργαλεία είναι αυτά που ανήκουν στην οικογένεια xUnit (JUnit, CppUnit, NUnit κ.α).
|
|
||||||
|
|
||||||
Τα εργαλεία αυτά μπορούν συνήθως κάλλιστα να συνεργαστούν μαζί με άλλα εργαλεία ανάπτυξης έτσι ώστε να είναι πολύ εύκολο για τον προγραμματιστή να συμπεριλάβει την διαδικασία unit testing στην υλοποίηση του κάθε συστήματος.
|
|
||||||
|
|
||||||
\section {Easy!Appointments testing}
|
|
||||||
Η συγγραφή των unit tests για το Easy!Appointments έγινε με την χρήση της ενσωματωμένης βιβλιοθήκης που παρέχει το CodeIgniter. Η βιβλιοθήκη παρέχει τις βασικές λειτουργίες ελέγχου και παραγωγής αναφορών για τα tests του κώδικα. Προτιμήθηκε έναντι του phpunit λόγω της καλύτερης απόδοσης σε σχέση με το CodeIgniter Framework.
|
|
||||||
|
|
||||||
Η διαδικασία της δοκιμής του συστήματος ξεκίνησε από τα models, τις λειτουργικές μονάδες που διαχειρίζονται την κίνηση των δεδομένων προς και από την βάση δεδομένων. Είναι απαραίτητο για το σύστημα να κατέχει ακέραια δεδομένα μιας και όλη η εφαρμογή βασίζεται σε αυτά. Η κάθε μέθοδος του κάθε model δοκιμάστηκε ξεχωριστά από τις υπόλοιπες για 3-5 διαφορετικές περιπτώσεις. Όσο αναπτύσσεται το σύστημα τόσο αυξάνονται και unit tests.
|
|
||||||
|
|
||||||
\begin{figure}[h]
|
|
||||||
\centering
|
|
||||||
\includegraphics[width=150mm]{images/ea-unit-testing.png}
|
|
||||||
\caption{Στιγμιότυπο της σελίδας εμφάνισης αποτελεσμάτων των unit tests.}
|
|
||||||
\label{ea-unit-testing}
|
|
||||||
\end{figure}
|
|
||||||
|
|
||||||
Για να γίνει αυτόματη εκτέλεση όλων των unit test που αντιστοιχούν σε ένα συγκεκριμένο model γράφτηκε η παρακάτω μέθοδος η οποία αφού ελέγξει τα ονόματα των test μεθόδων, εκτελεί μόνο εκείνα τα οποία ξεκινούν από την λέξη "test". Έτσι αν κάποια μέθοδος δεν είναι έτοιμη ή δεν πρέπει να συμπεριληφθεί στην εκτέλεση των unit test αρκεί να αλλάξει την αρχή του ονόματος της και η μέθοδος δεν θα την λάβει υπόψιν.
|
|
||||||
|
|
||||||
\lstinputlisting{snippets/unit_test_automation.php}
|
|
||||||
|
|
||||||
\section {Παραδείγματα}
|
|
||||||
Στον παρακάτω κώδικα δοκιμάζεται η βασική ροή της περίπτωσης χρήσης “προσθήκη ραντεβού”. Σε αυτό το test case η είσοδος της μεθόδου add() είναι σωστή και αναμένεται ότι και το αποτέλεσμα της διαδικασίας θα είναι επιτυχές. Στο τέλος αφαιρείται η εγγραφή που προστέθηκε για να μην μείνουν κατάλοιπα στην βάση. Σε κάθε unit test χρησιμοποιείται μόνο μια μέθοδος του model. Έτσι το κάθε test δεν επηρεάζεται από τυχόν προβλήματα σε άλλες μεθόδους του model.
|
|
||||||
|
|
||||||
\lstinputlisting{snippets/unit_test_insert_example.php}
|
|
||||||
|
|
||||||
Στο παρακάτω unit test δοκιμάζεται η μέθοδος get\_value() η οποία επιστρέφει την τιμή ενός πεδίου από την βάση. Στο συγκεκριμένο test case δίνεται ως παράμετρος ένα id εγγραφής το οποίο δεν υπάρχει στην βάση. Η αναμενόμενη συμπεριφορά από το model είναι να εμφανιστεί ένα exception το οποίο να ειδοποιεί ότι η εγγραφή με το συγκεκριμένο id δεν βρέθηκε στην βάση.
|
|
||||||
|
|
||||||
\lstinputlisting{snippets/unit_test_get_value_example.php}
|
|
||||||
|
|
||||||
Κάποια unit test δοκιμάζουν τις μεθόδους για σωστές τιμές και αναμένουν την επιτυχή ολοκλήρωση των διαδικασιών τους. Τα περισσότερα όμως tests σκοπό έχουν να δουν την συμπεριφορά του συστήματος για τιμές οι οποίες δεν είναι φυσιολογικές. Με αυτόν τον τρόπο μπορούν να προβλεφθούν πολλά bug και άλλα προβλήματα στον κώδικα και η εφαρμογή να είναι περισσότερο αξιόπιστη και δυνατή απέναντι σε σφάλματα.
|
|
|
@ -1,22 +0,0 @@
|
||||||
%% ΣΕΝΑΡΙΑ ΧΡΗΣΗΣ
|
|
||||||
%% Σε αυτό το κεφάλαιο γίνεται περιγραφή ενός σεναρίου χρήσης του συστήματος
|
|
||||||
%% για κάθε έναν από τους ρόλους των χρηστών της εφαρμογής.
|
|
||||||
|
|
||||||
\chapter{Σενάρια Χρήσης}
|
|
||||||
Το κεφάλαιο αυτό έχει ως στόχο να δώσει μια τυπική περιγραφή της χρήσης της εφαρμογής για όλους τους διαθέσιμους ρόλους των χρηστών της, έτσι ώστε να γίνει περισσότερο κατανοητός ο τρόπος με τον οποίον λειτουργεί το σύστημα κρατήσεων ραντεβού.
|
|
||||||
|
|
||||||
%% ΣΕΝΑΡΙΟ ΧΡΗΣΗΣ ΔΙΑΧΕΙΡΙΣΤΗ
|
|
||||||
\section{Σενάριο χρήσης διαχειριστή}
|
|
||||||
Μετά από αρκετό καιρό χρήσης του Easy!Appointments η εταιρεία προσθέτει μια νέα υπηρεσία στο ενεργητικό της και για τον σκοπό αυτό ανοίγει ένα νέο τμήμα υπαλλήλων. Ο διαχειριστής του συστήματος πρέπει να ενημερώσει την εφαρμογή και να προσθέσει την νέα υπηρεσία καθώς και τους νέους πάροχους υπηρεσιών, έτσι ώστε να μπορούν οι πελάτες να κλείνουν ραντεβού μαζί τους από εδώ και πέρα. Εφόσον γίνει αυτό οι πελάτες θα μπορούν να επιλέξουν τις αντίστοιχες εγγραφές από την φόρμα κράτησης ραντεβού.
|
|
||||||
|
|
||||||
%% ΣΕΝΑΡΙΟ ΧΡΗΣΗ ΠΑΡΟΧΟΥ ΥΠΗΡΕΣΙΩΝ
|
|
||||||
\section{Σενάριο χρήσης πάροχου υπηρεσιών}
|
|
||||||
Ο πάροχος υπηρεσιών της εφαρμογής λαμβάνει μια ειδοποίηση από την εφαρμογή (email) ότι έχει γίνει μια κράτηση για ραντεβού. Βλέποντας τα στοιχεία της κράτησης και την ημερομηνία αποφασίζει ότι δεν θα μπορέσει να είναι εκείνη την στιγμή διαθέσιμος, οπότε συνδέεται στην εφαρμογή και αλλάζει την ημερομηνία του ραντεβού. Αμέσως μετά πηγαίνει στο πρόγραμμά του και ενημερώνει την χρονική στιγμή στην οποία δεν θα είναι διαθέσιμος έτσι ώστε να μην μπορούν πλέον οι πελάτες να κάνουν κρατήσεις σε εκείνη την χρονική περίοδο. Στην συνέχεια αποστέλλεται ειδοποίηση στον πελάτη και αυτός μπορεί να κρίνει αν τον βολεύει η νέα ημερομηνία. Αν όχι θα πρέπει να ακυρώσει το ραντεβού και να το ξανά-προσθέσει σε κάποια άλλη χρονική στιγμή.
|
|
||||||
|
|
||||||
%% ΣΕΝΑΡΙΟ ΧΡΗΣΗΣ ΠΕΛΑΤΗ
|
|
||||||
\section{Σενάριο χρήσης πελάτη}
|
|
||||||
Ο πελάτης ενδιαφέρεται να κλείσει ραντεβού στην επιχείρηση για μια συγκεκριμένη υπηρεσία. Πηγαίνει στην σελίδα της επιχείρησης και βλέπει το πλάνο, αφού έχει επιλέξει ποια υπηρεσία και ποιόν υπάλληλο επιθυμεί. Στην συνέχεια επιλέγει μια χρονική στιγμή που τον βολεύει και την κατοχυρώνει. Η διαδικασία ολοκληρώνεται με την αποστολή ενός email προς τον πελάτη το οποίο περιέχει όλες τις πληροφορίες του ραντεβού, έτσι ώστε να είναι πάντα προσβάσιμες. Σε αυτό το email περιέχεται και ένας υπερσύνδεσμος ο οποίος επιτρέπει στον πελάτη να πραγματοποιήσει αλλαγές στο ραντεβού. Από την στιγμή αυτήν και μετά το ραντεβού έχει κατοχυρωθεί και ο πελάτης θα ενημερώνεται για οποιαδήποτε αλλαγή μπορεί να γίνει στο ραντεβού του με email.
|
|
||||||
|
|
||||||
%% ΣΕΝΑΡΙΟ ΧΡΗΣΗΣ ΓΡΑΜΜΑΤΕΑ
|
|
||||||
\section{Σενάριο χρήσης γραμματέα}
|
|
||||||
Ένας από τους πάροχους υπηρεσίας έχει κλειστεί εντελώς από ραντεβού και δεν μπορεί να δεχτεί άλλα για αυτήν την εβδομάδα. Ένας άλλος πάροχος προσφέρεται να βοηθήσει και έτσι κάποια ραντεβού πρέπει να μεταφερθούν στο ημερολογιακό πλάνο του δεύτερου πάροχου. Την διαδικασία αυτήν θα πρέπει να την αναλάβει η γραμματεία γιατί όλοι οι άλλοι είναι πολύ απασχολημένοι με το να εξυπηρετήσουν τους πελάτες τους.
|
|
|
@ -1,162 +0,0 @@
|
||||||
%% ΠΕΡΙΓΡΑΦΗ ΠΕΡΙΠΤΩΣΕΩΝ ΧΡΗΣΗΣ
|
|
||||||
%% Σε αυτό το κεφάλαιο γίνεται αναλυτική περιγραφή των περιπτώσεων χρήσης
|
|
||||||
%% του συστήματος κρατήσεων ραντεβου (βασική και εναλλακτικές ροές).
|
|
||||||
|
|
||||||
\chapter{Περιπτώσεις Χρήσης}
|
|
||||||
Σε αυτό το κεφάλαιο θα γίνει η αναλυτική περιγραφή των περιπτώσεων χρήσης του συστήματος που υλοποιήθηκε. Θα περιγραφούν τόσο η βασική ροή όσο και οι εναλλακτικές ροές για όλες τις περιπτώσεις χρήσης. Το κεφάλαιο χωρίζεται σε τμήματα ανάλογα με τον ρόλο (actor) της εφαρμογής στον οποίο ανήκουν.
|
|
||||||
|
|
||||||
\section{Πελάτης}
|
|
||||||
\subsection{Κράτηση ραντεβού}
|
|
||||||
Η βασικότερη περίπτωση χρήσης της εφαρμογής είναι η διαδικασία της κράτησης ραντεβού του πελάτη με έναν πάροχο υπηρεσίας για την υπηρεσία που τον ενδιαφέρει. Πρόκειται για την κυριότερη περίπτωση χρήσης, μιας και το σύστημα έχει ως στόχο την ευκολότερη διαχείριση των ραντεβού με τους πελάτες.
|
|
||||||
|
|
||||||
\textbf{ΒΑΣΙΚΗ ΡΟΗ}
|
|
||||||
|
|
||||||
Ο χρήστης μπαίνει στην σελίδα κράτησης ραντεβού και επιλέγει την υπηρεσία και τον πάροχο που τον ενδιαφέρει. Στην συνέχεια θα χρειαστεί να επιλέξει μια από τις διαθέσιμες ημερομηνίες και ώρες για να κλείσει το ραντεβού του. Αφού γίνει και αυτό θα πρέπει να συμπληρώσει τα στοιχεία του στην φόρμα που θα εμφανιστεί έτσι ώστε να μπορέσει η εταιρεία να έρθει σε επαφή μαζί του αν χρειαστεί. Τέλος ένα email θα σταλθεί πίσω στον πελάτη ότι το ραντεβού του έχει καταχωρηθεί με επιτυχία. Σε αυτό το email θα εμπεριέχεται και ένα link το οποίο θα του επιτρέπει να κάνει τροποποιήσει ή και να ακυρώσει το συγκεκριμένο ραντεβού.
|
|
||||||
|
|
||||||
\textbf{ΕΝΑΛΛΑΚΤΙΚΕΣ ΡΟΕΣ}
|
|
||||||
|
|
||||||
\begin{itemize}
|
|
||||||
\item Αν ο πελάτης αργήσει να επιλέξει ημερομηνία και στο ενδιάμεσο τον προλάβει ένας άλλος θα πρέπει να επιστραφεί μήνυμα το οποίο θα τον προτρέψει να βρει άλλη ημερομηνία και ώρα για το ραντεβού του.
|
|
||||||
\item Όταν ο πελάτης συμπληρώσει τα στοιχεία του και αφήσει κενό ένα πεδίο το οποίο είναι υποχρεωτικό για να ολοκληρωθεί η διαδικασία, θα εμφανιστεί μήνυμα το οποίο θα τον προτρέψει να συμπληρώσει όλα τα υποχρεωτικά πεδία.
|
|
||||||
\end{itemize}
|
|
||||||
|
|
||||||
\begin{figure}[ht!]
|
|
||||||
\centering
|
|
||||||
\includegraphics[width=130mm]{images/book-appointment.jpg}
|
|
||||||
\caption{Σελίδα κράτησης ραντεβού.}
|
|
||||||
\label{book-appointment}
|
|
||||||
\end{figure}
|
|
||||||
|
|
||||||
\begin{figure}[ht!]
|
|
||||||
\centering
|
|
||||||
\includegraphics[width=130mm]{images/backend-calendar.jpg}
|
|
||||||
\caption{Σελίδα διαχείρισης ραντεβού.}
|
|
||||||
\label{backend-calendar}
|
|
||||||
\end{figure}
|
|
||||||
|
|
||||||
\begin{figure}[ht!]
|
|
||||||
\centering
|
|
||||||
\includegraphics[width=130mm]{images/backend-providers.jpg}
|
|
||||||
\caption{Σελίδα διαχείρισης πάροχων υπηρεσιών.}
|
|
||||||
\label{backend-providers}
|
|
||||||
\end{figure}
|
|
||||||
|
|
||||||
\begin{figure}[ht!]
|
|
||||||
\centering
|
|
||||||
\includegraphics[width=130mm]{images/backend-settings.jpg}
|
|
||||||
\caption{Σελίδα ρυθμίσεων συστήματος.}
|
|
||||||
\label{book-settings}
|
|
||||||
\end{figure}
|
|
||||||
|
|
||||||
\subsection{Επεξεργασία - ακύρωση ραντεβού}
|
|
||||||
Εφόσον καταχωρηθεί ένα ραντεβού είναι πολύ σημαντικό να μπορέσει και να τροποποιηθεί με κάποιον τρόπο. Το σύστημα από την στιγμή που καταχωρεί ένα ραντεβού κρατάει και τα στοιχεία του πελάτη σε μια εγγραφή. Παρ' όλα αυτά δεν θα ήταν καλό να αναγκάζει τον πελάτη να δημιουργεί νέο χρήστη (με username και password) έτσι ώστε να μπορέσει να κάνει αλλαγές. Κάτι τέτοιο θα μείωνε την αποδοτικότητα της εφαρμογής μιας και προσθέτει ένα επιπλέον βήμα στην όλη διαδικασία, το οποίο μάλιστα θεωρείται εκνευριστικό αφού ένας μέσος χρήστης του διαδικτύου θα χρειαστεί να δημιουργήσει δεκάδες λογαριασμούς σε διάφορες ιστοσελίδες. Λαμβάνοντας αυτά υπόψιν για να μπορέσει ο πελάτης να πραγματοποιήσει αλλαγές ή και ακύρωση σε κάποιο ραντεβού του θα ακολουθεί έναν μοναδικό σύνδεσμο ο οποίος θα του έρχεται με email.
|
|
||||||
|
|
||||||
\textbf{ΒΑΣΙΚΗ ΡΟΗ}
|
|
||||||
|
|
||||||
Ο χρήστης ολοκληρώνει την διαδικασία κράτησης ραντεβού. Σε αυτήν την διαδικασία έχει ήδη δώσει το email του στο οποίο στέλνεται ένα email με τις πληροφορίες του ραντεβού που έχει κάνει κράτηση και μαζί έναν σύνδεσμο ο οποίος επιτρέπει στον χρήστη να πραγματοποιήσει αλλαγές στο συγκεκριμένο ραντεβού ή και να το ακυρώσει. Αφού ο χρήστης ακολουθήσει τον σύνδεσμο θα βρεθεί σε μια σελίδα η οποία θα περιέχει τις πληροφορίες του ραντεβού και θα του επιτρέπει να πραγματοποιήσει αλλαγές. Όταν ολοκληρώσει την διαδικασία θα πατάει ένα κουμπί το οποίο θα αποθηκεύει τις αλλαγές και ένα νέο email θα έρχεται πάλι στον χρήστη αλλά και στον συγκεκριμένο πάροχο ότι έχουν πραγματοποιηθεί αλλαγές στο πλάνο του.
|
|
||||||
|
|
||||||
\textbf{ΕΝΑΛΛΑΚΤΙΚΕΣ ΡΟΕΣ}
|
|
||||||
|
|
||||||
\begin{itemize}
|
|
||||||
\item Ο χρήστης μπορεί εν τέλη να μην θέλει να αποθηκεύσει τις αλλαγές του και έτσι να κλείσει την σελίδα.
|
|
||||||
\item Ο διαχειριστής του συστήματος μπορεί να έχει ορίσει ένα χρονικό περιθώριο πριν το ραντεβού, στο οποίο δεν επιτρέπεται να γίνονται αλλαγές (λόγω σταθερότητας του πλάνου). Αν ο χρήστης βρίσκεται μέσα σε αυτό το περιθώριο τότε θα εμφανιστεί μήνυμα το οποίο θα τον ενημερώνει για τον λόγο τον οποίο δεν μπορεί να πραγματοποιήσει αλλαγές στο ραντεβού του.
|
|
||||||
\end{itemize}
|
|
||||||
|
|
||||||
\section {Πάροχος Υπηρεσιών}
|
|
||||||
\subsection {Συγχρονισμός πλάνου με το Google Calendar}
|
|
||||||
Βασικό στοιχείο για την χρησιμότητα και την απόδοση του συστήματος είναι η διαχείριση των δεδομένων να γίνεται από πολλά συστήματα. Κάτι τέτοιο μπορεί να επιτευχθεί με τον συγχρονισμό των ραντεβού με το Google Calendar API. Σε αυτό ο χρήστης θα μπορεί να πραγματοποιεί αλλαγές στο πλάνο του μέσω του Google Calendar και αυτές να εφαρμόζονται και στο σύστημα κρατήσεων ραντεβού κάνοντας έτσι την εργασία του πολύ εύκολη.
|
|
||||||
|
|
||||||
\textbf{ΒΑΣΙΚΗ ΡΟΗ}
|
|
||||||
|
|
||||||
Ο χρήστης βλέπει το πλάνο του μέσω της υπηρεσίας Google Calendar και προσθέτει ένα συμβάν κατά την διάρκεια του οποίο δεν είναι διαθέσιμος. Έπειτα από λίγο τρέχει χειροκίνητα τον συγχρονισμό από το Easy!Appointments και αυτό ανακαλύπτει ότι υπάρχει ένα νέο συμβάν στο Google Calendar το οποίο δεν είναι καταχωρημένο στην βάση δεδομένων του. Αμέσως μετά παίρνει τα στοιχεία του νέου συμβάντος μέσω του API που παρέχει η Google και το αποθηκεύει στην βάση δεδομένων έτσι ώστε να μην είναι διαθέσιμος ο πάροχος την συγκεκριμένη χρονική στιγμή. Την επόμενη φορά που θα πάει ένας πελάτης να κλείσει ραντεβού με τον συγκεκριμένο πάροχο θα δει ότι το συγκεκριμένο χρονικό διάστημα δεν είναι διαθέσιμο.
|
|
||||||
|
|
||||||
\textbf{ΕΝΑΛΛΑΚΤΙΚΕΣ ΡΟΕΣ}
|
|
||||||
|
|
||||||
\begin{itemize}
|
|
||||||
\item Πιθανό είναι να γίνει μια αλλαγή σε ένα συγχρονισμένο συμβάν στο Google Calendar το οποίο όμως να έχει αλλαχθεί και στο Easy!Appointments. Σε αυτήν την περίπτωση θεωρείται ότι υπερισχύει η αλλαγή που έχει γίνει στο Easy!Appointments διότι δεν υπάρχει η δυνατότητα να ελεγχθεί και στα δύο συστήματα το ποια χρονική στιγμή έχει γίνει η τροποποίηση.
|
|
||||||
\end{itemize}
|
|
||||||
|
|
||||||
\subsection {Διαχείριση ραντεβού}
|
|
||||||
Όπως και ο πελάτης, έτσι και ο πάροχος υπηρεσιών θα πρέπει να έχει την δυνατότητα να διαχειρίζεται τα ραντεβού του. Με αυτόν τον τρόπο θα έχει την δυνατότητα να πραγματοποιεί αλλαγές στο ημερολόγιο του, να αλλάζει την ημερομηνία των ραντεβού του και να καθορίζει το πλάνο του καταπώς τον βολεύει. Το Easy!Appointments εμφανίζει όλα τα ραντεβού σε ημερολόγιο, στο οποίο ο χρήστης μπορεί να περιηγηθεί χρονικά.
|
|
||||||
|
|
||||||
\textbf{ΒΑΣΙΚΗ ΡΟΗ}
|
|
||||||
|
|
||||||
Ο χρήστης ενημερώνεται από τον προϊστάμενο του ότι θα πρέπει να πραγματοποιήσει κάποια εργασία σε ένα χρονικό διάστημα στο οποίο υπάρχουν καταχωρημένα ραντεβού με πελάτες της εταιρείας. Κάποια από τα ραντεβού μπορεί να τα αναλάβει κάποιος άλλος πάροχος και για αυτόν τον λόγο ο χρήστης επεξεργάζεται αυτά τα ραντεβού και αλλάζει τον πάροχο τους έτσι ώστε να μετατεθούν στο πλάνου του αντίστοιχου χρήστη. Όσα περισσέψουν θα χρειαστεί να τα μεταφέρει χρονικά ή να τα διαγράψει προτείνοντας στους πελάτες να κλείσουν κάποια άλλη στιγμή.
|
|
||||||
|
|
||||||
\textbf{ΕΝΑΛΛΑΚΤΙΚΕΣ ΡΟΕΣ}
|
|
||||||
|
|
||||||
\begin{itemize}
|
|
||||||
\item Καθώς ο πάροχος υπηρεσιών επεξεργάζεται ένα ραντεβού μπορεί να αποφασίσει ότι δεν θέλει να αποθηκεύσει τις αλλαγές που έχει κάνει και έτσι πατάει το κουμπί ακύρωσης αποτρέποντας την ενημέρωση των δεδομένων στην βάση.
|
|
||||||
\item Σε αντίθεση με τον πελάτη, ένας πάροχος υπηρεσιών μπορεί να αλλάξει την διάρκεια ενός ραντεβού ανεξάρτητα από το πόση ώρα διαρκεί η υπηρεσία που θα παρέχει. Οπότε στην φόρμα επεξεργασίας ενός ραντεβού υπάρχει η δυνατότητα επιλογής ημερομηνίας και ώρας έναρξης και τερματισμού του ραντεβού.
|
|
||||||
\end{itemize}
|
|
||||||
|
|
||||||
\subsection{Λήψη ειδοποιήσεων από το σύστημα}
|
|
||||||
Κάθε φορά που πραγματοποιείται μια ενέργεια που αφορά κάποιο ραντεβού στο σύστημα ο πάροχος υπηρεσίας θα ενημερώνεται με email (εκτός και αν απενεργοποιήσει αυτήν την ρύθμιση). Έτσι θα είναι πάντα ενήμερος σχετικά με την κατάσταση των ραντεβού του. Σε αυτά τα μηνύματα θα περιέχεται και ένα μοναδικό link το οποίο θα δίνει την δυνατότητα στον πάροχο να πραγματοποιήσει αλλαγές γρήγορα στο ραντεβού που τον ενδιαφέρει.
|
|
||||||
|
|
||||||
\textbf{ΒΑΣΙΚΗ ΡΟΗ}
|
|
||||||
|
|
||||||
Ο πάροχος υπηρεσιών μπαίνει στο σύστημα και πραγματοποιεί αλλαγές σε ένα ήδη καταχωρημένο ραντεβού. Με την αποθήκευση των αλλαγών αυτός και ο πελάτης θα λάβουν ένα email στο οποίο θα φαίνονται τα νέα στοιχεία του ραντεβού. Με αυτόν τον τρόπο μπορεί να επαληθευθεί ότι οι αλλαγές που έγιναν είναι σωστές και επίσης δίνεται η δυνατότητα στον χρήστη να χρησιμοποιήσει το link του ραντεβού για να πραγματοποιήσει άλλες αλλαγές, αν αυτό είναι απαραίτητο.
|
|
||||||
|
|
||||||
\subsection {Διαχείριση Πελατών}
|
|
||||||
Από την στιγμή που ένας πάροχος θα έχει το δικαίωμα να επεξεργαστεί τις πληροφορίες ενός ραντεβού θα μπορεί να επεξεργάζεται και τα στοιχεία των πελατών που υπάγονται σε αυτό. Με αυτήν την δυνατότητα θα μπορεί να είναι σε θέση να ενημερώσει κάποια πεδία στην εγγραφή του πελάτη τα οποία είναι πιθανώς λανθασμένα ή και να προσθέσει νέες πληροφορίες.
|
|
||||||
|
|
||||||
\textbf{ΒΑΣΙΚΗ ΡΟΗ}
|
|
||||||
|
|
||||||
Ο πάροχος μπαίνει στο σύστημα και επιλέγει να επεξεργαστεί κάποιο ραντεβού. Στην οθόνη επεξεργασίας του ραντεβού θα μπορέσει να τροποποιήσει και τα στοιχεία των πελατών. Όταν είναι έτοιμος μπορεί να αποθηκεύσει τις αλλαγές στην βάση δεδομένων.
|
|
||||||
|
|
||||||
\textbf{ΕΝΑΛΛΑΚΤΙΚΕΣ ΡΟΕΣ}
|
|
||||||
|
|
||||||
Ο πάροχος μπορεί να αλλάξει τα στοιχεία ενός πελάτη χωρίς να πραγματοποιήσει αλλαγές στις πληροφορίες του ραντεβού του ίδιου.
|
|
||||||
|
|
||||||
\section{Γραμματέας}
|
|
||||||
\subsection{Διαχείριση ραντεβού}
|
|
||||||
Ο χρήστης γραμματέας μπορεί να πραγματοποιήσει αλλαγές στα ραντεβού ενός ή περισσοτέρων πάροχων υπηρεσίας. Με αυτόν τον τρόπο μια εταιρεία μπορεί να αναθέσει όλη την διαχείριση των ραντεβού σε ένα άτομο και οι πάροχοι απλώς να βλέπουν τα ραντεβού τους στο πλάνο.
|
|
||||||
|
|
||||||
\textbf{ΒΑΣΙΚΗ ΡΟΗ}
|
|
||||||
|
|
||||||
Ο χρήστης γραμματέας δέχεται τηλεφώνημα από κάποιον πελάτη ο οποίος επιθυμεί να αλλάξει την ώρα του ραντεβού του αλλά δεν έχει σύνδεση με το διαδίκτυο στο σημείο που βρίσκεται. Έτσι ο γραμματέας πραγματοποιεί την αλλαγή του ραντεβού καταπώς μπορεί να βολεύει τόσο τον πάροχο υπηρεσίας όσο και τον πελάτη. Όταν τελειώσει μπορεί να αποθηκεύσει τις αλλαγές στο σύστημα.
|
|
||||||
|
|
||||||
\subsection{Διαχείριση πελατών}
|
|
||||||
Εκτός των ραντεβού, ο χρήστης γραμματέας είναι σε θέση να πραγματοποιήσει αλλαγές και στα στοιχεία των πελατών οργανώνοντας και κρατώντας πλήρη πελατολόγιο για την επιχείριση. Μελλοντικά θα είναι σε θέση να βρίσκει πολύ εύκολα οποιονδήποτε πελάτη της επιχείρισης και να βλέπει τα στοιχεία του.
|
|
||||||
|
|
||||||
\textbf{ΒΑΣΙΚΗ ΡΟΗ}
|
|
||||||
|
|
||||||
Ο γραμματέας πηγαίνει στο backend στην σελίδα τον πελατών και φιλτράρει τον πελάτη που τον ενδιαφέρει και αμέσως βλέπει τα στοιχεία του. Πολύ εύκολα μπορεί να πραγματοποιήσει αλλαγές αλλά και να τον διαγράψει από το σύστημα.
|
|
||||||
|
|
||||||
\textbf{ΕΝΑΛΛΑΚΤΙΚΕΣ ΡΟΕΣ}
|
|
||||||
|
|
||||||
\begin{itemize}
|
|
||||||
\item Ο γραμματέας μπορεί να επεξεργαστεί τα στοιχεία ενός πελάτη και την στιγμή που επεξεργάζεται ένα ραντεβού. Παρόλα αυτά σε αυτήν την περίπτωση κυρίαρχη οντότητα είναι το ραντεβού και έτσι ο χρήστης δεν έχει την δυνατότητα να φιλτράρει τους πελάτες καταπώς θέλει. Επίσης ένας πελάτης μπορεί να διαγραφεί μόνο όταν διαγραφεί και το ραντεβού του.
|
|
||||||
\end{itemize}
|
|
||||||
|
|
||||||
\section{Διαχειριστής}
|
|
||||||
\subsection{Εγκατάσταση της εφαρμογής}
|
|
||||||
Αυτή η περίπτωση χρήσης περιλαμβάνει την ρύθμιση του server όπου θα τρέξει το Easy!Appointments και την δημιουργία του λογαριασμού του διαχειριστή. Επίσης μπορεί να καθοριστούν και τα κλειδιά που απαιτούνται για την χρήση του Google Calendar API.
|
|
||||||
|
|
||||||
\textbf{ΒΑΣΙΚΗ ΡΟΗ}
|
|
||||||
|
|
||||||
Ο διαχειριστής τοποθετεί τα αρχεία της εφαρμογής στον server του και πηγαίνει με τον περιηγητή στην διεύθυνση που δείχνει τον κύριο κατάλογο. Η εφαρμογή καταλαβαίνει ότι δεν έχει ακόμα πραγματοποιηθεί εγκατάσταση και μεταφέρει τον χρήστη στην διαδικασία εγκατάστασης. Σε αυτήν την διαδικασία ο διαχειριστής θα πρέπει να ορίσει σημαντικά στοιχεία που αφορούν την λειτουργία του συστήματος και τα στοιχεία του λογαριασμού του. Όλα αυτά τα στοιχεία βέβαια θα είναι διαθέσιμα προς επεξεργασία από την αντίστοιχη σελίδα στο backend.
|
|
||||||
|
|
||||||
\subsection{Παραμετροποίηση της εφαρμογής}
|
|
||||||
Για να μπορέσει να λειτουργήσει η εφαρμογή σύμφωνα με την μορφή της επιχείρησης θα χρειαστεί να παραμετροποιηθεί από τον διαχειριστή. Η παραμετροποίηση περιλαμβάνει τα ωράρια λειτουργίας της επιχείρησης, την διαχείριση των υπηρεσιών που θα είναι διαθέσιμες προς το κοινό καθώς και την διαχείριση των πάροχων υπηρεσιών.
|
|
||||||
|
|
||||||
\textbf{ΒΑΣΙΚΗ ΡΟΗ}
|
|
||||||
|
|
||||||
Ο διαχειριστής εισέρχεται στο backend μέρος της εφαρμογής και επιλέγει την σελίδα των ρυθμίσεων. Εκεί έχει την δυνατότητα να θέσει τις τιμές σε διάφορες παραμέτρους οι οποίες καθορίζουν τον τρόπο με τον οποίο λειτουργεί το σύστημα. Στόχος είναι αυτός να συμβαδίζει με τον τρόπο λειτουργίας της επιχείρισης έτσι ώστε να μπορεί η εταιρεία να επωφεληθεί από το Easy!Appointments.
|
|
||||||
|
|
||||||
\subsection{Διαχείριση ραντεβού}
|
|
||||||
Ο διαχειριστής ως χρήστης έχει πρόσβαση σε όλες τις πληροφορίες του συστήματος. Έτσι μπορεί να μεταβάλει και να προσθέσει ραντεβού στο σύστημα σαν να ήταν ένας πάροχος υπηρεσιών ή ένας χρήστης γραμματέας.
|
|
||||||
|
|
||||||
\textbf {ΒΑΣΙΚΗ ΡΟΗ}
|
|
||||||
|
|
||||||
Ο διαχειριστής συνδέεται στο backend μέρος της εφαρμογής και πηγαίνει στην σελίδα του ημερολογίου. Εκεί μπορεί να δει τα ραντεβού όλων των πάροχων υπηρεσιών και να πραγματοποιήσει αλλαγές σε αυτά. Με το που αποθηκευτούν οι αλλαγές σε ένα ραντεβού ο πελάτης και ο πάροχος θα ενημερωθούν με email, όπως θα γινόταν δηλαδή αν την επεξεργασία την έκανε ένας πάροχος.
|
|
||||||
|
|
||||||
\subsection {Διαχείριση χρηστών}
|
|
||||||
Τις υπηρεσίες που προσφέρει η εταιρεία τις αναλαμβάνουν κάποιοι υπάλληλοι (ή ομάδες υπαλλήλων), οι οποίοι αναφέρονται στο σύστημα ως πάροχοι υπηρεσιών. Τα στοιχεία τους και τις αρμοδιότητές τους μέσα στο σύστημα τα ορίζει μόνο ο διαχειριστής του συστήματος, από το backend μέρος της εφαρμογής. Επίσης είναι δυνατή η διαχείριση των διαχειριστών, γραμματειών και πελατών του συστήματος.
|
|
||||||
|
|
||||||
\textbf{ΒΑΣΙΚΗ ΡΟΗ}
|
|
||||||
|
|
||||||
Ο διαχειριστής της εφαρμογής συνδέεται στο backend και πηγαίνει στην σελίδα των πάροχων υπηρεσίας. Εκεί βλέπει μια λίστα με τους ήδη καταχωρημένους πάροχους. Αν θέλει μπορεί να προσθέσει έναν καινούργιο χρήστη ή να επεξεργαστεί και να διαγράψει κάποια εγγραφή που υπάρχει ήδη στην βάση δεδομένων.
|
|
||||||
|
|
||||||
\subsection {Διαχείριση υπηρεσιών}
|
|
||||||
Οι πελάτες που θα επισκέπτονται τον ιστότοπο του Easy!Appointments της επιχείρησης θα κλείνουν ραντεβού για συγκεκριμένες υπηρεσίες. Το ποιες υπηρεσίες θα είναι διαθέσιμες και ποιοι πάροχοι υπηρεσιών μπορούν να εξυπηρετήσουν τι, το διαχειρίζεται ο διαχειριστής του συστήματος. Αποτελεί υποπερίπτωση χρήσης της παραμετροποίησης της εφαρμογής.
|
|
|
@ -1,30 +0,0 @@
|
||||||
<?php
|
|
||||||
/**
|
|
||||||
* Find the database record id of an admin user.
|
|
||||||
*
|
|
||||||
* @param array $admin Contains the admin data. The 'email'
|
|
||||||
* value is required in order to find the record id.
|
|
||||||
* @return int Returns the record id
|
|
||||||
* @throws Exception When the 'email' value is not present
|
|
||||||
* on the $admin array.
|
|
||||||
*/
|
|
||||||
public function find_record_id($admin) {
|
|
||||||
if (!isset($admin['email'])) {
|
|
||||||
throw new Exception('Admin email was not provided: '
|
|
||||||
. print_r($admin, TRUE));
|
|
||||||
}
|
|
||||||
|
|
||||||
$result = $this->db
|
|
||||||
->select('ea_users.id')
|
|
||||||
->from('ea_users')
|
|
||||||
->join('ea_roles', 'ea_roles.id = ea_users.id_roles', 'inner')
|
|
||||||
->where('ea_users.email', $admin['email'])
|
|
||||||
->where('ea_roles.slug', DB_SLUG_ADMIN)
|
|
||||||
->get();
|
|
||||||
|
|
||||||
if ($result->num_rows() == 0) {
|
|
||||||
throw new Exception('Could not find admin record id.');
|
|
||||||
}
|
|
||||||
|
|
||||||
return intval($result->row()->id);
|
|
||||||
}
|
|
|
@ -1,168 +0,0 @@
|
||||||
<?php
|
|
||||||
/**
|
|
||||||
* Full synchronization of appointments between Google
|
|
||||||
* Calendar and Easy!Appointments.
|
|
||||||
*
|
|
||||||
* This method will completely sync the appointments of a provider
|
|
||||||
* with his Google Calendar account. The sync period needs to be
|
|
||||||
* relatively small, because a lot of API calls might be necessary
|
|
||||||
* and this will lead to consuming the Google limit for the Calendar
|
|
||||||
* API usage.
|
|
||||||
*
|
|
||||||
* @param numeric $provider_id Provider record to be synced.
|
|
||||||
*/
|
|
||||||
public function sync($provider_id = NULL) {
|
|
||||||
try {
|
|
||||||
// The user must be logged in.
|
|
||||||
$this->load->library('session');
|
|
||||||
if ($this->session->userdata('user_id') == FALSE) return;
|
|
||||||
|
|
||||||
if ($provider_id === NULL) {
|
|
||||||
throw new Exception('Provider id not specified.');
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->load->model('appointments_model');
|
|
||||||
$this->load->model('providers_model');
|
|
||||||
$this->load->model('services_model');
|
|
||||||
$this->load->model('customers_model');
|
|
||||||
$this->load->model('settings_model');
|
|
||||||
|
|
||||||
$provider = $this->providers_model->get_row($provider_id);
|
|
||||||
|
|
||||||
// Check whether the selected provider has google sync enabled.
|
|
||||||
$google_sync = $this->providers_model
|
|
||||||
->get_setting('google_sync', $provider['id']);
|
|
||||||
if (!$google_sync) {
|
|
||||||
throw new Exception('The selected provider has not the '
|
|
||||||
. 'Google synchronization setting enabled.');
|
|
||||||
}
|
|
||||||
|
|
||||||
$google_token = json_decode($this->providers_model
|
|
||||||
->get_setting('google_token', $provider['id']));
|
|
||||||
$this->load->library('google_sync');
|
|
||||||
$this->google_sync->refresh_token($google_token->refresh_token);
|
|
||||||
|
|
||||||
// Fetch provider's appointments that belong to the sync
|
|
||||||
// time period.
|
|
||||||
$sync_past_days = $this->providers_model
|
|
||||||
->get_setting('sync_past_days', $provider['id']);
|
|
||||||
$sync_future_days = $this->providers_model
|
|
||||||
->get_setting('sync_future_days', $provider['id']);
|
|
||||||
$start = strtotime('-' . $sync_past_days
|
|
||||||
. ' days', strtotime(date('Y-m-d')));
|
|
||||||
$end = strtotime('+' . $sync_future_days
|
|
||||||
. ' days', strtotime(date('Y-m-d')));
|
|
||||||
|
|
||||||
$where_clause = array(
|
|
||||||
'start_datetime >=' => date('Y-m-d H:i:s', $start),
|
|
||||||
'end_datetime <=' => date('Y-m-d H:i:s', $end),
|
|
||||||
'id_users_provider' => $provider['id']
|
|
||||||
);
|
|
||||||
|
|
||||||
$appointments =
|
|
||||||
$this->appointments_model->get_batch($where_clause);
|
|
||||||
|
|
||||||
$company_settings = array(
|
|
||||||
'company_name' => $this->settings_model
|
|
||||||
->get_setting('company_name'),
|
|
||||||
'company_link' => $this->settings_model
|
|
||||||
->get_setting('company_link'),
|
|
||||||
'company_email' => $this->settings_model
|
|
||||||
->get_setting('company_email')
|
|
||||||
);
|
|
||||||
|
|
||||||
// Sync each appointment with Google Calendar by following
|
|
||||||
// the project's sync protocol (see documentation).
|
|
||||||
foreach($appointments as $appointment) {
|
|
||||||
if ($appointment['is_unavailable'] == FALSE) {
|
|
||||||
$service = $this->services_model
|
|
||||||
->get_row($appointment['id_services']);
|
|
||||||
$customer = $this->customers_model
|
|
||||||
->get_row($appointment['id_users_customer']);
|
|
||||||
} else {
|
|
||||||
$service = NULL;
|
|
||||||
$customer = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If current appointment not synced yet, add to gcal.
|
|
||||||
if ($appointment['id_google_calendar'] == NULL) {
|
|
||||||
$google_event = $this->google_sync
|
|
||||||
->add_appointment($appointment, $provider,
|
|
||||||
$service, $customer, $company_settings);
|
|
||||||
$appointment['id_google_calendar'] = $google_event->id;
|
|
||||||
$this->appointments_model->add($appointment);// Save gcal id
|
|
||||||
} else {
|
|
||||||
// Appointment is synced with google calendar.
|
|
||||||
try {
|
|
||||||
$google_event = $this->google_sync
|
|
||||||
->get_event($appointment['id_google_calendar']);
|
|
||||||
|
|
||||||
if ($google_event->status == 'cancelled') {
|
|
||||||
throw new Exception('Event is cancelled, remove the '
|
|
||||||
. 'record from Easy!Appointments.');
|
|
||||||
}
|
|
||||||
|
|
||||||
// If gcal event is different from e!a appointment
|
|
||||||
// then update e!a record.
|
|
||||||
$is_different = FALSE;
|
|
||||||
$appt_start = strtotime($appointment['start_datetime']);
|
|
||||||
$appt_end = strtotime($appointment['end_datetime']);
|
|
||||||
$event_start =
|
|
||||||
strtotime($google_event->getStart()->getDateTime());
|
|
||||||
$event_end =
|
|
||||||
strtotime($google_event->getEnd()->getDateTime());
|
|
||||||
|
|
||||||
if ($appt_start != $event_start
|
|
||||||
|| $appt_end != $event_end) {
|
|
||||||
$is_different = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($is_different) {
|
|
||||||
$appointment['start_datetime'] =
|
|
||||||
date('Y-m-d H:i:s', $event_start);
|
|
||||||
$appointment['end_datetime'] =
|
|
||||||
date('Y-m-d H:i:s', $event_end);
|
|
||||||
$this->appointments_model->add($appointment);
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch(Exception $exc) {
|
|
||||||
// Appointment not found on gcal, delete from e!a.
|
|
||||||
$this->appointments_model->delete($appointment['id']);
|
|
||||||
$appointment['id_google_calendar'] = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// :: ADD GCAL EVENTS THAT ARE NOT PRESENT ON E!A
|
|
||||||
$events = $this->google_sync->get_sync_events($start, $end);
|
|
||||||
|
|
||||||
foreach($events->getItems() as $event) {
|
|
||||||
$results = $this->appointments_model->get_batch(
|
|
||||||
array('id_google_calendar' => $event->getId()));
|
|
||||||
if (count($results) == 0) {
|
|
||||||
// Record doesn't exist in E!A, so add the event now.
|
|
||||||
$appointment = array(
|
|
||||||
'start_datetime' => date('Y-m-d H:i:s',
|
|
||||||
strtotime($event->start->getDateTime())),
|
|
||||||
'end_datetime' => date('Y-m-d H:i:s',
|
|
||||||
strtotime($event->end->getDateTime())),
|
|
||||||
'is_unavailable' => TRUE,
|
|
||||||
'notes' => $event->getSummary()
|
|
||||||
. ' ' . $event->getDescription(),
|
|
||||||
'id_users_provider' => $provider_id,
|
|
||||||
'id_google_calendar' => $event->getId(),
|
|
||||||
'id_users_customer' => NULL,
|
|
||||||
'id_services' => NULL,
|
|
||||||
);
|
|
||||||
$this->appointments_model->add($appointment);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
echo json_encode(AJAX_SUCCESS);
|
|
||||||
|
|
||||||
} catch(Exception $exc) {
|
|
||||||
echo json_encode(array(
|
|
||||||
'exceptions' => array($exc)
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,108 +0,0 @@
|
||||||
<?php
|
|
||||||
/**
|
|
||||||
* [AJAX] Get the available appointment hours for the given date.
|
|
||||||
*
|
|
||||||
* This method answers to an AJAX request. It calculates the
|
|
||||||
* available hours for thegiven service, provider and date.
|
|
||||||
*
|
|
||||||
* @param numeric $_POST['provider_id'] The selected provider's
|
|
||||||
* record id.
|
|
||||||
* @param string $_POST['selected_date'] The selected date of
|
|
||||||
* which the available hours we want to see.
|
|
||||||
* @param numeric $_POST['service_duration'] The selected service
|
|
||||||
* duration in minutes.
|
|
||||||
* @param string $_POST['manage_mode'] Contains either 'true' or
|
|
||||||
* 'false' and determines the if current user is managing an already
|
|
||||||
* booked appointment or not.
|
|
||||||
* @return Returns a json object with the available hours.
|
|
||||||
*/
|
|
||||||
public function ajax_get_available_hours() {
|
|
||||||
$this->load->model('providers_model');
|
|
||||||
$this->load->model('appointments_model');
|
|
||||||
$this->load->model('settings_model');
|
|
||||||
|
|
||||||
try {
|
|
||||||
// If manage mode is TRUE then the following we should not
|
|
||||||
// consider the selected appointment when calculating the
|
|
||||||
// available time periods of the provider.
|
|
||||||
$exclude_appointments = ($_POST['manage_mode'] === 'true')
|
|
||||||
? array($_POST['appointment_id'])
|
|
||||||
: array();
|
|
||||||
|
|
||||||
$empty_periods = $this->get_provider_available_time_periods(
|
|
||||||
$_POST['provider_id'], $_POST['selected_date'],
|
|
||||||
$exclude_appointments);
|
|
||||||
|
|
||||||
// Calculate the available appointment hours for the given
|
|
||||||
// date. The empty spaces are broken down to 15 min and if
|
|
||||||
// the service fit in each quarter then a new available hour
|
|
||||||
// is added to the "$available_hours" array.
|
|
||||||
|
|
||||||
$available_hours = array();
|
|
||||||
|
|
||||||
foreach ($empty_periods as $period) {
|
|
||||||
$start_hour = new DateTime($_POST['selected_date']
|
|
||||||
. ' ' . $period['start']);
|
|
||||||
$end_hour = new DateTime($_POST['selected_date']
|
|
||||||
. ' ' . $period['end']);
|
|
||||||
|
|
||||||
$minutes = $start_hour->format('i');
|
|
||||||
|
|
||||||
if ($minutes % 15 != 0) {
|
|
||||||
// Change the start hour of the current space in
|
|
||||||
// order to be on of the following: 00, 15, 30, 45.
|
|
||||||
if ($minutes < 15) {
|
|
||||||
$start_hour->setTime($start_hour->format('H'), 15);
|
|
||||||
} else if ($minutes < 30) {
|
|
||||||
$start_hour->setTime($start_hour->format('H'), 30);
|
|
||||||
} else if ($minutes < 45) {
|
|
||||||
$start_hour->setTime($start_hour->format('H'), 45);
|
|
||||||
} else {
|
|
||||||
$start_hour->setTime($start_hour->format('H') + 1, 00);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$current_hour = $start_hour;
|
|
||||||
$diff = $current_hour->diff($end_hour);
|
|
||||||
|
|
||||||
while (($diff->h * 60 + $diff->i)
|
|
||||||
> intval($_POST['service_duration'])) {
|
|
||||||
$available_hours[] = $current_hour->format('H:i');
|
|
||||||
$current_hour->add(new DateInterval("PT15M"));
|
|
||||||
$diff = $current_hour->diff($end_hour);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the selected date is today, remove past hours. It is
|
|
||||||
// important include the timeout before booking that is set
|
|
||||||
// in the backoffice the system. Normally we might want the
|
|
||||||
// customer to book an appointment that is at least half or
|
|
||||||
// one hour from now. The setting is stored in minutes.
|
|
||||||
if (date('m/d/Y', strtotime($_POST['selected_date']))
|
|
||||||
== date('m/d/Y')) {
|
|
||||||
if ($_POST['manage_mode'] === 'true') {
|
|
||||||
$book_advance_timeout = 0;
|
|
||||||
} else {
|
|
||||||
$book_advance_timeout =
|
|
||||||
$this->settings_model->get_setting('book_advance_timeout');
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach($available_hours as $index => $value) {
|
|
||||||
$available_hour = strtotime($value);
|
|
||||||
$current_hour = strtotime('+' . $book_advance_timeout
|
|
||||||
. ' minutes', strtotime('now'));
|
|
||||||
if ($available_hour <= $current_hour) {
|
|
||||||
unset($available_hours[$index]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$available_hours = array_values($available_hours);
|
|
||||||
echo json_encode($available_hours);
|
|
||||||
|
|
||||||
} catch(Exception $exc) {
|
|
||||||
echo json_encode(array(
|
|
||||||
'exceptions' => array(exceptionToJavaScript($exc))
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,139 +0,0 @@
|
||||||
<?php
|
|
||||||
/**
|
|
||||||
* Get an array containing the free time periods (start - end) of a
|
|
||||||
* selected date.
|
|
||||||
*
|
|
||||||
* This method is very important because there are many cases where
|
|
||||||
* the system needs to know when a provider is avaible for an
|
|
||||||
* appointment. This method will return an array that belongs to the
|
|
||||||
* selected date and contains values that have the start and the end
|
|
||||||
* time of an available time period.
|
|
||||||
*
|
|
||||||
* @param numeric $provider_id The provider's record id.
|
|
||||||
* @param string $selected_date The date to be checked (MySQL
|
|
||||||
* formatted string).
|
|
||||||
* @param array $exclude_appointments This array contains the ids of
|
|
||||||
* the appointments that will not be taken into consideration when the
|
|
||||||
* available time periods are calculated.
|
|
||||||
* @return array Returns an array with the available time periods of
|
|
||||||
* the provider.
|
|
||||||
*/
|
|
||||||
private function get_provider_available_time_periods($provider_id,
|
|
||||||
$selected_date, $exclude_appointments = array()) {
|
|
||||||
$this->load->model('appointments_model');
|
|
||||||
$this->load->model('providers_model');
|
|
||||||
|
|
||||||
// Get the provider's working plan and reserved appointments.
|
|
||||||
$working_plan = json_decode($this->providers_model
|
|
||||||
->get_setting('working_plan', $provider_id), true);
|
|
||||||
|
|
||||||
$where_clause = array(
|
|
||||||
'DATE(start_datetime)'=>date('Y-m-d', strtotime($selected_date)),
|
|
||||||
'id_users_provider'=>$provider_id
|
|
||||||
);
|
|
||||||
|
|
||||||
$reserved_appointments = $this->appointments_model
|
|
||||||
->get_batch($where_clause);
|
|
||||||
|
|
||||||
// Sometimes it might be necessary to not take into account some
|
|
||||||
// appointment records in order to display what the providers'
|
|
||||||
// available time periods would be without them.
|
|
||||||
foreach ($exclude_appointments as $excluded_id) {
|
|
||||||
foreach ($reserved_appointments as $index => $reserved) {
|
|
||||||
if ($reserved['id'] == $excluded_id) {
|
|
||||||
unset($reserved_appointments[$index]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find the empty spaces on the plan. The first split between the
|
|
||||||
// plan is due to a break (if exist). After that every reserved
|
|
||||||
// appointment is considered to be a taken space in the plan.
|
|
||||||
$selected_date_working_plan =
|
|
||||||
$working_plan[strtolower(date('l', strtotime($selected_date)))];
|
|
||||||
$available_periods_with_breaks = array();
|
|
||||||
|
|
||||||
if (isset($selected_date_working_plan['breaks'])) {
|
|
||||||
foreach($selected_date_working_plan['breaks'] as $index=>$break){
|
|
||||||
// Split the working plan to available time periods that do not
|
|
||||||
// contain the breaks in them.
|
|
||||||
$last_break_index = $index - 1;
|
|
||||||
|
|
||||||
if (count($available_periods_with_breaks) === 0) {
|
|
||||||
$start_hour = $selected_date_working_plan['start'];
|
|
||||||
$end_hour = $break['start'];
|
|
||||||
} else {
|
|
||||||
$start_hour = $selected_date_working_plan['breaks']
|
|
||||||
[$last_break_index]['end'];
|
|
||||||
$end_hour = $break['start'];
|
|
||||||
}
|
|
||||||
|
|
||||||
$available_periods_with_breaks[] = array(
|
|
||||||
'start' => $start_hour,
|
|
||||||
'end' => $end_hour
|
|
||||||
);
|
|
||||||
}
|
|
||||||
// Add the period from the last break to the end of the day.
|
|
||||||
$available_periods_with_breaks[] = array(
|
|
||||||
'start'=>$selected_date_working_plan['breaks'][$index]['end'],
|
|
||||||
'end'=>$selected_date_working_plan['end']
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Break the empty periods with the reserved appointments.
|
|
||||||
$available_periods_with_appointments =
|
|
||||||
$available_periods_with_breaks;
|
|
||||||
|
|
||||||
foreach($reserved_appointments as $appointment) {
|
|
||||||
foreach($available_periods_with_appointments as $index=>&$period){
|
|
||||||
$a_start =
|
|
||||||
date('H:i',strtotime($appointment['start_datetime']));
|
|
||||||
$a_end =
|
|
||||||
date('H:i', strtotime($appointment['end_datetime']));
|
|
||||||
$p_start =
|
|
||||||
date('H:i', strtotime($period['start']));
|
|
||||||
$p_end =
|
|
||||||
date('H:i', strtotime($period['end']));
|
|
||||||
|
|
||||||
if ($a_start <= $p_start && $a_end <= $p_end
|
|
||||||
&& $a_end <= $p_start) {
|
|
||||||
// The appointment does not belong in this time period, so
|
|
||||||
// we will not change anything.
|
|
||||||
} else if ($a_start <= $p_start && $a_end <= $p_end
|
|
||||||
&& $a_end >= $p_start) {
|
|
||||||
// The appointment starts before the period and finishes
|
|
||||||
// somewhere inside.We will need to break this period and
|
|
||||||
// leave the available part.
|
|
||||||
$period['start'] = $a_end;
|
|
||||||
} else if ($a_start >= $p_start && $a_end <= $p_start) {
|
|
||||||
// The appointment is inside the time period, so we will
|
|
||||||
// split the period into two new others.
|
|
||||||
unset($available_periods_with_appointments[$index]);
|
|
||||||
$available_periods_with_appointments[] = array(
|
|
||||||
'start' => $p_start,
|
|
||||||
'end' => $a_start
|
|
||||||
);
|
|
||||||
$available_periods_with_appointments[] = array(
|
|
||||||
'start' => $a_end,
|
|
||||||
'end' => $p_end
|
|
||||||
);
|
|
||||||
} else if ($a_start >= $p_start && $a_end >= $p_start
|
|
||||||
&& $a_start <= $p_end) {
|
|
||||||
// The appointment starts in the period and finishes out
|
|
||||||
// of it. We will need to remove the time that is taken
|
|
||||||
// from the appointment.
|
|
||||||
$period['end'] = $a_start;
|
|
||||||
} else if ($a_start >= $p_start && $a_end >= $p_end
|
|
||||||
&& $a_start >= $p_end) {
|
|
||||||
// The appointment does not belong in the period so do not
|
|
||||||
// change anything.
|
|
||||||
} else if ($a_start <= $p_start && $a_end >= $p_end
|
|
||||||
&& $a_start <= $p_end) {
|
|
||||||
// The appointment is bigger than the period, so this period
|
|
||||||
// needs to be removed.
|
|
||||||
unset($available_periods_with_appointments[$index]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return array_values($available_periods_with_appointments);
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
<?php
|
|
||||||
/**
|
|
||||||
* Run all the available tests.
|
|
||||||
*/
|
|
||||||
public function run_all() {
|
|
||||||
// All the methods whose names start with "test" are going to be
|
|
||||||
// executed. If you want a method to not be executed remove the
|
|
||||||
// "test" keyword from the beginning.
|
|
||||||
$class_methods = get_class_methods('Unit_tests_admins_model');
|
|
||||||
foreach ($class_methods as $method_name) {
|
|
||||||
if (substr($method_name, 0, 5) === 'test_') {
|
|
||||||
call_user_func(array($this, $method_name));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,22 +0,0 @@
|
||||||
<?php
|
|
||||||
/**
|
|
||||||
* Test the get field value method with a record id that
|
|
||||||
* doesn't exist in the db.
|
|
||||||
*
|
|
||||||
* A database exception is expected.
|
|
||||||
*/
|
|
||||||
private function test_get_value_record_does_not_exist() {
|
|
||||||
$random_record_id = 843521368768;
|
|
||||||
|
|
||||||
$has_thrown_exception = FALSE;
|
|
||||||
|
|
||||||
try {
|
|
||||||
$this->CI->Appointments_Model
|
|
||||||
->get_value('start_datetime', $random_record_id);
|
|
||||||
} catch (InvalidArgumentException $db_exc) {
|
|
||||||
$has_thrown_exception = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->CI->unit->run($has_thrown_exception, TRUE,
|
|
||||||
'Test get_value() with record id that does not exist.');
|
|
||||||
}
|
|
|
@ -1,31 +0,0 @@
|
||||||
<?php
|
|
||||||
/**
|
|
||||||
* Test the appointment add method - insert new record.
|
|
||||||
*/
|
|
||||||
private function test_add_appointment_insert() {
|
|
||||||
// Add - insert new appointment record to the database.
|
|
||||||
$appointment_data = array(
|
|
||||||
'start_datetime' => '2013-05-01 12:30:00',
|
|
||||||
'end_datetime' => '2013-05-01 13:00:00',
|
|
||||||
'notes' => 'Some notes right here...',
|
|
||||||
'id_users_provider' => $this->provider_id,
|
|
||||||
'id_users_customer' => $this->customer_id,
|
|
||||||
'id_services' => $this->service_id
|
|
||||||
);
|
|
||||||
$appointment_data['id'] = $this->CI->Appointments_Model
|
|
||||||
->add($appointment_data);
|
|
||||||
$this->CI->unit->run($appointment_data['id'], 'is_int',
|
|
||||||
'Test if add() appointment (insert operation) '
|
|
||||||
. 'returned the db row id.');
|
|
||||||
|
|
||||||
// Check if the record is the one that was inserted.
|
|
||||||
$db_data = $this->CI->db->get_where('ea_appointments',
|
|
||||||
array('id' => $appointment_data['id']))->row_array();
|
|
||||||
$this->CI->unit->run($appointment_data, $db_data, 'Test if add() '
|
|
||||||
. 'appointment (insert operation) has successfully '
|
|
||||||
. 'inserted a record.');
|
|
||||||
|
|
||||||
// Delete inserted record.
|
|
||||||
$this->CI->db->delete('ea_appointments',
|
|
||||||
array('id' => $appointment_data['id']));
|
|
||||||
}
|
|
|
@ -1,21 +0,0 @@
|
||||||
@misc {
|
|
||||||
google_calendar_api,
|
|
||||||
title = "Google Calendar API",
|
|
||||||
url = "https://developers.google.com/google-apps/calendar/",
|
|
||||||
year = "2013"
|
|
||||||
}
|
|
||||||
|
|
||||||
@misc {
|
|
||||||
codeigniter_reference,
|
|
||||||
author = "",
|
|
||||||
title = "CodeIgniter Reference",
|
|
||||||
url = "http://ellislab.com/codeigniter/user-guide/toc.html",
|
|
||||||
year = "2013"
|
|
||||||
}
|
|
||||||
|
|
||||||
@misc {
|
|
||||||
software_engineering_notes,
|
|
||||||
author = "Νικόλαος Πεταλίδης",
|
|
||||||
title = "Σημειώσεις των μαθημάτων Τεχνολογία Λογισμικού 1 \& 2.",
|
|
||||||
year = "2012"
|
|
||||||
}
|
|
|
@ -1,454 +0,0 @@
|
||||||
% ΤΕΙ Σερρών
|
|
||||||
% Σχολή Τεχνολογικών Εφαρμογών
|
|
||||||
% Τμήμα Πληροφορικής και Επικοινωνιών
|
|
||||||
% Πτυχιακή εργασία
|
|
||||||
%
|
|
||||||
% Nicholaos Petalidis, 15/08/1998
|
|
||||||
% icdthesis.sty Style file for TEI of SERRES, ICD, final year
|
|
||||||
% dissertation thesis
|
|
||||||
% Copyright (C) yyyy name of author
|
|
||||||
|
|
||||||
% This program is free software; you can redistribute it and/or
|
|
||||||
% modify it under the terms of the GNU General Public License
|
|
||||||
% as published by the Free Software Foundation; either version 2
|
|
||||||
% of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
% This program is distributed in the hope that it will be useful,
|
|
||||||
% but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
% GNU General Public License for more details.
|
|
||||||
|
|
||||||
% You should have received a copy of the GNU General Public License
|
|
||||||
% along with this program; if not, write to the Free Software
|
|
||||||
% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
||||||
%---------------------------Identification Part--------------------------------
|
|
||||||
\NeedsTeXFormat{LaTeX2e}
|
|
||||||
\ProvidesPackage{icdthesisUTF}
|
|
||||||
|
|
||||||
%--------------------------Initial Code----------------------------------------
|
|
||||||
|
|
||||||
% This part is empty
|
|
||||||
|
|
||||||
%--------------------------Declaration of Options------------------------------
|
|
||||||
\DeclareOption{a4paper}{\setlength{\paperheight}{297mm}%
|
|
||||||
\setlength{\paperwidth}{210mm}}
|
|
||||||
|
|
||||||
\ExecuteOptions{a4paper,12pt}
|
|
||||||
\ProcessOptions
|
|
||||||
|
|
||||||
%-------------------------Package Loading--------------------------------------
|
|
||||||
\RequirePackage{polyglossia}
|
|
||||||
\RequirePackage{fontspec} % necessary of XeTeX
|
|
||||||
\RequirePackage{xunicode} % Unicode from accented glyphs
|
|
||||||
\RequirePackage{xltxtra} % loads fixltx2e, etex, xunicode, fontspec
|
|
||||||
%\RequirePackage{xgreek} % for greek documents
|
|
||||||
\RequirePackage[backend=biber,bibencoding=utf8,natbib=false,bibstyle=authoryear,citestyle=authoryear,babel=hyphen]{biblatex}
|
|
||||||
\RequirePackage{ifthen}
|
|
||||||
\RequirePackage{url}
|
|
||||||
\RequirePackage{csquotes}
|
|
||||||
\RequirePackage[font=small,format=plain,labelfont=bf]{caption}
|
|
||||||
\setdefaultlanguage{greek}
|
|
||||||
\setotherlanguage{english}
|
|
||||||
|
|
||||||
%set fonts required by the guidelines
|
|
||||||
\setmainfont[Mapping=tex-text]{Times New Roman}
|
|
||||||
\setmonofont[Mapping=tex-text]{Courier New}
|
|
||||||
|
|
||||||
%\setmonofont[Script=Latin,Mapping=tex-text]{Courier New}
|
|
||||||
%\newfontfamily\greekfont[Script=Greek,Mapping=tex-text]{Times New Roman}
|
|
||||||
%Redefine greek font family because some fonts although they have greek glyphs they
|
|
||||||
%do not explicitly support the Greek script
|
|
||||||
\newfontfamily\greekfont[Mapping=tex-text]{Times New Roman}
|
|
||||||
\newfontfamily\greekfonttt[Mapping=tex-text]{Courier New}
|
|
||||||
\newfontfamily\greekfontsf[Mapping=tex-text]{Arial}
|
|
||||||
|
|
||||||
\gappto\captionsgreek{\renewcommand{\figurename}{Διάγραμμα}}
|
|
||||||
\gappto\captionsgreek{\renewcommand{\listfigurename}{Κατάλογος διαγραμμάτων}}
|
|
||||||
%--------------------------- Main Code-----------------------------------------
|
|
||||||
|
|
||||||
\typeout{----------------------------------------------------------------------}
|
|
||||||
\typeout{- Τμήμα Μηχανικών Πληροφορικής ΤΕ }
|
|
||||||
\typeout{- ΤΕΙ Κεντρικής Μακεδονίας, version 0.4, 05/11/2013 }
|
|
||||||
\typeout{- Nicholaos Petalidis, nikos <at> petalidis.gr }
|
|
||||||
\typeout{-----------------------------------------------------------------------}
|
|
||||||
|
|
||||||
%\tracingmacros=1
|
|
||||||
%\tracingcommands=1
|
|
||||||
|
|
||||||
%-----------------------Set up margins-----------------------------------------
|
|
||||||
|
|
||||||
% Define hoffset to be -1in. This way calculations start from 0in
|
|
||||||
% from the left side of the paper instead of 1in.
|
|
||||||
|
|
||||||
\setlength{\hoffset}{-1in}
|
|
||||||
|
|
||||||
% Define the left margin to be 40mm
|
|
||||||
% No need to set evensidemargin for one-sided printing
|
|
||||||
% 40mm = 114pt
|
|
||||||
\setlength{\oddsidemargin}{114pt}
|
|
||||||
|
|
||||||
% Define the right margin to be 15mm
|
|
||||||
% Leave the marginparsep unchanged
|
|
||||||
% Set the maginparwidth to be the remaining space from marginparsep
|
|
||||||
% 25mm = 71pt
|
|
||||||
\setlength{\marginparwidth}{71pt}
|
|
||||||
\addtolength{\marginparwidth}{-\marginparsep}
|
|
||||||
\setlength{\marginparpush}{0mm}
|
|
||||||
% Calculate the textwidth:
|
|
||||||
% This is a bit difficult. The standard says there must be around 60-70
|
|
||||||
% characters per line... I reckon that a textwidth of around 120mm
|
|
||||||
% should give 60-70 characters of 11pt size.
|
|
||||||
% On the other hand I don't like the output, (lines look too short)
|
|
||||||
% so I have put it to the maximum: 14.5mm = 413pt
|
|
||||||
|
|
||||||
\setlength{\textwidth}{413pt}
|
|
||||||
|
|
||||||
% An update:
|
|
||||||
% The width of the a4 : 210mm
|
|
||||||
% The width of the left margin : 40mm
|
|
||||||
% The width of the right margin: 25mm
|
|
||||||
% The width of the text: 145mm
|
|
||||||
|
|
||||||
% The standard says ``all other margins should be at least 15mm''
|
|
||||||
% This includes the top and bottom margin
|
|
||||||
|
|
||||||
% Define voffset to be -1in. This way calculations start from 0in
|
|
||||||
% from the top side of the paper instead of 1in.
|
|
||||||
|
|
||||||
\setlength{\voffset}{-1in}
|
|
||||||
|
|
||||||
% Define the topmargin to be 15mm
|
|
||||||
% This is the minimum recommended top margin
|
|
||||||
|
|
||||||
\setlength{\topmargin}{43pt}
|
|
||||||
|
|
||||||
% Define the distance between the heading (page number) and the text
|
|
||||||
% to be 8mm = 23pt
|
|
||||||
|
|
||||||
\setlength{\headsep}{23pt}
|
|
||||||
|
|
||||||
% Define the height of a heading to be 12pt
|
|
||||||
|
|
||||||
\setlength{\headheight}{12pt}
|
|
||||||
|
|
||||||
% Define the distance between the bottom of a footnote and
|
|
||||||
% the bottom of the text to be 10.5mm=30pt
|
|
||||||
|
|
||||||
\setlength{\footskip}{30pt}
|
|
||||||
|
|
||||||
% Change the textheight so that the bottom margin is 15mm=43pt
|
|
||||||
\setlength{\textheight}{695pt}
|
|
||||||
|
|
||||||
|
|
||||||
%------------------Typography--------------------------------------------------
|
|
||||||
|
|
||||||
%Paragraphs should be indented 5-10mm with no additional space between
|
|
||||||
%paragraphs. I set the indent to be 7.5 mm
|
|
||||||
\setlength{\parindent}{7.5mm}
|
|
||||||
|
|
||||||
%Set the spacing between lines to one and a half
|
|
||||||
\renewcommand{\baselinestretch }{1.5}
|
|
||||||
|
|
||||||
%----------Set up commands----------------------------------------------------
|
|
||||||
\newcommand{\thesistitle}{A title}
|
|
||||||
\newcommand{\thesisauthorsex}{male}
|
|
||||||
\newcommand{\thesisauthor}{Ένας Σπουδαστής}
|
|
||||||
\newcommand{\thesisauthorabbrv}{Ε. Σπουδαστής}
|
|
||||||
\newcommand{\thesisauthorinitials}{ΕΑ}
|
|
||||||
\newcommand{\thesisSecondAuthor}{}
|
|
||||||
\newcommand{\thesisSecondAuthorabbrv}{Ε. Σπουδαστής}
|
|
||||||
\newcommand{\thesisSecondAuthorInitials}{}
|
|
||||||
\newcommand{\thesissupervisor}{Ν. Πεταλίδης}
|
|
||||||
\newcommand{\thesismonth}{August}
|
|
||||||
\newcommand{\thesistype}{Thesis}
|
|
||||||
\newcommand{\degreetitle}{Πτυχίο}
|
|
||||||
\newcommand{\degreetitleabbr}{Πτυχίο}
|
|
||||||
\newcommand{\thesisyear}{1900}
|
|
||||||
\newcommand{\thesisschool}{Σχολή Τεχνολογικών Εφαρμογών}
|
|
||||||
\newcommand{\thesisuniversity}{ΤΕΧΝΟΛΟΓΙΚΟ ΕΚΠΑΙΔΕΥΤΙΚΟ ΙΔΡΥΜΑ ΚΕΝΤΡΙΚΗΣ ΜΑΚΕΔΟΝΙΑΣ}
|
|
||||||
\newcommand{\thesisdepartment}{Τμήμα Μηχανικών Πληροφορικής ΤΕ}
|
|
||||||
|
|
||||||
%--------------------Format the page style-------------------------------------
|
|
||||||
%According to BS 4821 page numbers should appear at the top outer corner
|
|
||||||
% First define a heading that has a page number on the top outer corner
|
|
||||||
|
|
||||||
\renewcommand{\ps@myheadings}{%
|
|
||||||
\renewcommand{\@oddhead}{\hfil\thepage}%
|
|
||||||
\renewcommand{\@evenhead}{\@oddhead}%
|
|
||||||
\renewcommand{\@evenfoot}{}% empty
|
|
||||||
\renewcommand{\@oddfoot}{}% empty
|
|
||||||
}
|
|
||||||
|
|
||||||
% The standard wants page numbers to appear in the top outer corner.
|
|
||||||
% To overcome the problems with the \chapter, \tableofcontents
|
|
||||||
% pagestyles I redefine the plain page style to be that of myheadings
|
|
||||||
|
|
||||||
\let\ps@plain=\ps@myheadings
|
|
||||||
% Apparently most definitions use @mkboth instead of markboth.
|
|
||||||
% This command does nothing in myheadings so I have to redefine it
|
|
||||||
\renewcommand{\@mkboth}{\markboth}
|
|
||||||
% **************************TITLE PAGE**********************************
|
|
||||||
|
|
||||||
% A specimen is provided in the handbook for a title page.
|
|
||||||
% Apparenrtly the specimen is wrong and everything should be centered
|
|
||||||
% instead of being flushed-left. In that specimen the title and author
|
|
||||||
% name appears in upper case. I have it in upper case here as well.
|
|
||||||
\newcommand{\Titlepage}{
|
|
||||||
\thispagestyle{empty}
|
|
||||||
\begin{center}
|
|
||||||
%\fontsize{12pt}{\baselineskip}\selectfont
|
|
||||||
\MakeUppercase{\textbf{\thesisuniversity}}\\
|
|
||||||
\MakeUppercase{\textbf{\thesisschool}}\\
|
|
||||||
\MakeUppercase{\textbf{\thesisdepartment}}\\
|
|
||||||
\vfill
|
|
||||||
%\fontsize{16}{\baselineskip}\selectfont % The standard requires 16pt
|
|
||||||
% for the title page
|
|
||||||
\Large{\MakeUppercase{\textbf{\thesistitle}}}
|
|
||||||
%\fontsize{14}{\baselineskip}\selectfont % The standard requires 14pt
|
|
||||||
% for the title page
|
|
||||||
\vfill
|
|
||||||
\large{
|
|
||||||
\ifthenelse{\equal{\thesisSecondAuthor}{}}{
|
|
||||||
\ifthenelse{\equal{\thesisauthorsex}{male}}
|
|
||||||
{\textbf{Πτυχιακή εργασία του}\\\thesisauthor}
|
|
||||||
{\textbf{Πτυχιακή εργασία της}\\\thesisauthor}}
|
|
||||||
{\textbf{Πτυχιακή εργασία των}\\\thesisauthor\\\thesisSecondAuthor}
|
|
||||||
\\Επιβλέπων: \thesissupervisor}
|
|
||||||
\vfill
|
|
||||||
%\fontsize{12}{\baselineskip}\selectfont % The standard requires
|
|
||||||
\MakeUppercase{\textbf{ΣΕΡΡΕΣ, \thesismonth\ \thesisyear}}
|
|
||||||
\end{center}
|
|
||||||
% Make the default to be myheadings
|
|
||||||
\pagestyle{myheadings}
|
|
||||||
}
|
|
||||||
%**********************************************************************
|
|
||||||
|
|
||||||
% *****************************ABSTRACT********************************
|
|
||||||
% Not much information is provided about the abstract so I took
|
|
||||||
% the liberty of creating my own:-)
|
|
||||||
\newcommand{\thesisabstract}{Σύνοψη}
|
|
||||||
\newcommand{\@thesisabstract}{\thesisabstract}
|
|
||||||
|
|
||||||
\newenvironment{Abstract}
|
|
||||||
{
|
|
||||||
\chapter*{\@thesisabstract
|
|
||||||
\@mkboth{}
|
|
||||||
{}}
|
|
||||||
\addcontentsline{toc}{chapter}{\@thesisabstract}
|
|
||||||
}
|
|
||||||
{}
|
|
||||||
%**********************************************************************
|
|
||||||
|
|
||||||
% *************************ACKNOWLEDGEMENTS****************************
|
|
||||||
\newcommand{\thesisacknowledgementhead}{Ευχαριστίες}
|
|
||||||
\newcommand{\@thesisacknowledgementhead}{\thesisacknowledgementhead}
|
|
||||||
|
|
||||||
\newenvironment{Acknowledgement}
|
|
||||||
{
|
|
||||||
\chapter*{\@thesisacknowledgementhead
|
|
||||||
\@mkboth{}{}}
|
|
||||||
|
|
||||||
\addcontentsline{toc}{chapter}{\@thesisacknowledgementhead}
|
|
||||||
}
|
|
||||||
{}
|
|
||||||
%********************************************************************
|
|
||||||
|
|
||||||
% ******************************PREFACE******************************
|
|
||||||
\newcommand{\thesispreface}{Πρόλογος}
|
|
||||||
\newcommand{\@thesispreface}{\thesispreface}
|
|
||||||
|
|
||||||
\newenvironment{Preface}
|
|
||||||
{
|
|
||||||
\chapter*{\@thesispreface
|
|
||||||
\@mkboth{}{}}
|
|
||||||
|
|
||||||
\addcontentsline{toc}{chapter}{\@thesispreface}
|
|
||||||
}
|
|
||||||
{ }
|
|
||||||
%**********************************************************************
|
|
||||||
|
|
||||||
% ******************************AUTHORS DECLARATION********************
|
|
||||||
\newcommand{\thesisdeclaration}{Υπεύθυνη δήλωση}
|
|
||||||
\newcommand{\@thesisdeclaration}{\thesisdeclaration}
|
|
||||||
|
|
||||||
\newenvironment{Declaration}
|
|
||||||
{
|
|
||||||
\chapter*{\@thesisdeclaration
|
|
||||||
\@mkboth{}{}}
|
|
||||||
|
|
||||||
\addcontentsline{toc}{chapter}{\@thesisdeclaration}
|
|
||||||
}
|
|
||||||
{ }
|
|
||||||
\newcommand{\Declarationpage}{
|
|
||||||
\vfill
|
|
||||||
\begin{Declaration}
|
|
||||||
\textbf{\underline{Υπεύθυνη Δήλωση}}:
|
|
||||||
\ifthenelse{\equal{\thesisSecondAuthor}{}}{
|
|
||||||
Βεβαιώνω ότι είμαι συγγραφέας αυτής της πτυχιακής εργασίας και ότι κάθε βοήθεια
|
|
||||||
την οποία είχα για την προετοιμασία της, είναι πλήρως
|
|
||||||
αναγνωρισμένη και αναφέρεται στην πτυχιακή εργασία. Επίσης έχω
|
|
||||||
αναφέρει τις όποιες πηγές από τις οποίες έκανα χρήση δεδομένων,
|
|
||||||
ιδεών ή λέξεων, είτε αυτές αναφέρονται ακριβώς είτε
|
|
||||||
παραφρασμένες. Επίσης βεβαιώνω ότι αυτή η πτυχιακή εργασία
|
|
||||||
προετοιμάστηκε από εμένα προσωπικά ειδικά για τις απαιτήσεις του
|
|
||||||
προγράμματος σπουδών του Τμήματος Μηχανικών Πληροφορικής ΤΕ του Τ.Ε.Ι. Κεντρικής Μακεδονίας.
|
|
||||||
}
|
|
||||||
{Βεβαιώνουμε ότι είμαστε συγγραφείς αυτής της πτυχιακής εργασίας και ότι κάθε βοήθεια
|
|
||||||
την οποία είχαμε για την προετοιμασία της, είναι πλήρως
|
|
||||||
αναγνωρισμένη και αναφέρεται στην πτυχιακή εργασία. Επίσης έχουμε
|
|
||||||
αναφέρει τις όποιες πηγές από τις οποίες κάναμε χρήση δεδομένων,
|
|
||||||
ιδεών ή λέξεων, είτε αυτές αναφέρονται ακριβώς είτε
|
|
||||||
παραφρασμένες. Επίσης βεβαιώνουμε ότι αυτή η πτυχιακή εργασία
|
|
||||||
προετοιμάστηκε από εμάς προσωπικά ειδικά για τις απαιτήσεις του
|
|
||||||
προγράμματος σπουδών του Τμήματος Μηχανικών Πληροφορικής ΤΕ του Τ.Ε.Ι. Κεντρικής Μακεδονίας.}
|
|
||||||
|
|
||||||
\end{Declaration}
|
|
||||||
}
|
|
||||||
%**********************************************************************
|
|
||||||
|
|
||||||
|
|
||||||
% ******************************DEFINITIONS****************************
|
|
||||||
\newcommand{\thesisdefinitions}{Ορισμοί}
|
|
||||||
\newcommand{\@thesisdefinitions}{\thesisdefinitions}
|
|
||||||
|
|
||||||
\newenvironment{Definitions}
|
|
||||||
{
|
|
||||||
\chapter*{\@thesisdefinitions
|
|
||||||
\@mkboth{}{}}
|
|
||||||
|
|
||||||
\addcontentsline{toc}{chapter}{\@thesisdefinitions}
|
|
||||||
}
|
|
||||||
{}
|
|
||||||
|
|
||||||
%**********************************************************************
|
|
||||||
%****************************Starting the main text!*******************
|
|
||||||
% The following code tries to fix ``running heads''
|
|
||||||
% Running heads are not necessary but if they exist they should
|
|
||||||
% give the author's name with initials, year of submission and
|
|
||||||
% chapter number or heading
|
|
||||||
% First make it show the chapter number and heading
|
|
||||||
\renewcommand{\chaptermark}[1]{\markboth{\
|
|
||||||
\thechapter. #1}{\
|
|
||||||
\thechapter. #1}}
|
|
||||||
\renewcommand{\sectionmark}[1]{\markright{\thesection. #1}}
|
|
||||||
|
|
||||||
% Now redefine myheadings to include all the relevant information
|
|
||||||
\newcommand{\Startpage}{\renewcommand{\ps@myheadings}{%
|
|
||||||
\renewcommand{\@oddhead}{\leftmark,\
|
|
||||||
~\thesisauthorabbrv,\thesisSecondAuthorabbrv\
|
|
||||||
~\thesisyear\hfil\thepage}%
|
|
||||||
\renewcommand{\@evenhead}{\@oddhead}%
|
|
||||||
\renewcommand{\@evenfoot}{}% empty
|
|
||||||
\renewcommand{\@oddfoot}{}% empty
|
|
||||||
}
|
|
||||||
\pagestyle{myheadings}}
|
|
||||||
%**************************************************************************
|
|
||||||
|
|
||||||
%*******************************GLOSSARY*******************************
|
|
||||||
\newcommand{\thesisglossary}{Γλωσσάρι}
|
|
||||||
\newcommand{\@thesisglossary}{\thesisglossary}
|
|
||||||
|
|
||||||
\newenvironment{Glossary}
|
|
||||||
{
|
|
||||||
\chapter*{\@thesisglossary
|
|
||||||
\@mkboth{\thesisglossary}{\thesisglossary}}
|
|
||||||
|
|
||||||
\addcontentsline{toc}{chapter}{\@thesisglossary}
|
|
||||||
}
|
|
||||||
{ }
|
|
||||||
%**************************************************************************
|
|
||||||
|
|
||||||
%**********************************************************************
|
|
||||||
% Code shamelessly stolen follows now!
|
|
||||||
|
|
||||||
% ******************************APPENDIX*******************************
|
|
||||||
|
|
||||||
%% The following is taken from: csthesis.cls (Edinburgh University)
|
|
||||||
%% I changed the numbering to be arabic.
|
|
||||||
%% Redefine the appendix command to ensure that it does a pagebreak
|
|
||||||
%% (sorts problem of Appendix appearing in header of last page before
|
|
||||||
%% the first apppendix).
|
|
||||||
%%
|
|
||||||
%\renewcommand{\appendixname}{Παράρτημα}
|
|
||||||
\renewcommand{\appendix}{\vfill\pagebreak
|
|
||||||
\setcounter{chapter}{0}%
|
|
||||||
\setcounter{section}{0}%
|
|
||||||
\renewcommand\@chapapp{\appendixname}%
|
|
||||||
\renewcommand\chaptername{\appendixname}%
|
|
||||||
\renewcommand\thechapter{\@arabic\c@chapter}
|
|
||||||
}
|
|
||||||
|
|
||||||
%
|
|
||||||
% ************************Table of contents****************************
|
|
||||||
%
|
|
||||||
% The following code is taken from report.cls (c) LaTeX 3 Project
|
|
||||||
% I changed a little bit the definitions in order to produce running
|
|
||||||
% heads according to the BS standard
|
|
||||||
\renewcommand\tableofcontents{%
|
|
||||||
\if@twocolumn
|
|
||||||
\@restonecoltrue\onecolumn
|
|
||||||
\else
|
|
||||||
\@restonecolfalse
|
|
||||||
\fi
|
|
||||||
\chapter*{\contentsname
|
|
||||||
\@mkboth{%
|
|
||||||
\hfil\thepage}{\hfil\thepage}}%
|
|
||||||
\@starttoc{toc}%
|
|
||||||
\if@restonecol\twocolumn\fi
|
|
||||||
}
|
|
||||||
\renewcommand\listoffigures{%
|
|
||||||
\if@twocolumn
|
|
||||||
\@restonecoltrue\onecolumn
|
|
||||||
\else
|
|
||||||
\@restonecolfalse
|
|
||||||
\fi
|
|
||||||
\chapter*{\listfigurename
|
|
||||||
\@mkboth{\hfil\thepage}%
|
|
||||||
{\hfil\thepage}}%
|
|
||||||
\@starttoc{lof}%
|
|
||||||
\if@restonecol\twocolumn\fi
|
|
||||||
}
|
|
||||||
\renewcommand\listoftables{%
|
|
||||||
\if@twocolumn
|
|
||||||
\@restonecoltrue\onecolumn
|
|
||||||
\else
|
|
||||||
\@restonecolfalse
|
|
||||||
\fi
|
|
||||||
\chapter*{\listtablename
|
|
||||||
\@mkboth{%
|
|
||||||
\hfil\thepage}{\hfil\thepage}}%
|
|
||||||
\@starttoc{lot}%
|
|
||||||
\if@restonecol\twocolumn\fi
|
|
||||||
}
|
|
||||||
% ******************************REFERENCES*****************************
|
|
||||||
|
|
||||||
%%%
|
|
||||||
%%% Command from report.cls, (c) LaTeX3 Project.
|
|
||||||
%%%
|
|
||||||
% \renewenvironment{thebibliography}[1]
|
|
||||||
% {\chapter*{\bibname
|
|
||||||
% \@mkboth{\bibname}{\bibname}}%
|
|
||||||
% \addcontentsline{toc}{chapter}{\bibname}
|
|
||||||
% \list{\@biblabel{\@arabic\c@enumiv}}%
|
|
||||||
% {\settowidth\labelwidth{\@biblabel{#1}}%
|
|
||||||
% \leftmargin\labelwidth
|
|
||||||
% \advance\leftmargin\labelsep
|
|
||||||
% \@openbib@code
|
|
||||||
% \usecounter{enumiv}%
|
|
||||||
% \let\p@enumiv\@empty
|
|
||||||
% \renewcommand\theenumiv{\@arabic\c@enumiv}}%
|
|
||||||
% \sloppy
|
|
||||||
% \clubpenalty4000
|
|
||||||
% \@clubpenalty \clubpenalty
|
|
||||||
% \widowpenalty4000%
|
|
||||||
% \sfcode`\.\@m}
|
|
||||||
% {\def\@noitemerr
|
|
||||||
% {\@latex@warning{Empty `thebibliography' environment}}%
|
|
||||||
% \endlist}
|
|
||||||
\newcommand{\citep}[1]{\parencite{#1}}
|
|
||||||
|
|
||||||
\newcommand{\lastpageinfo}{\newpage
|
|
||||||
\vspace*{\fill}
|
|
||||||
\thispagestyle{empty}
|
|
||||||
\scriptsize{\noindent Η εργασία αυτή στοιχειοθετήθηκε με το πρόγραμμα \XeLaTeX. Για τη στοιχειοθέτηση της βιβλιογραφίας χρησιμοποιήθηκε το πρόγραμμα \texttt{biber} και \texttt{biblatex}. Οι γραμματοσειρές που χρησιμοποιήθηκαν είναι οι Times New Roman και \texttt{Courier New}.}
|
|
||||||
}
|
|
|
@ -1,27 +0,0 @@
|
||||||
%% -----------------------------------------------------------
|
|
||||||
%% EASY!APPOINTMENTS THESIS
|
|
||||||
%%
|
|
||||||
%% STUDENT : ALEXANDROS TSELEGIDIS
|
|
||||||
%% INSTITUTION : TEI SERRON
|
|
||||||
%% DEPARTMENT : INFORMATION AND COMMUNICATION SCIENCE
|
|
||||||
%% DATE : NOVEMBER 2013
|
|
||||||
%%
|
|
||||||
%% THIS FILE CONTAINS THE BSC THESIS FOR THE EASY!APPOINTMENTS
|
|
||||||
%% APPLICATION. THE DOCUMENT IS SPLIT INTO MULTIPLE FILES, IN
|
|
||||||
%% ORDER TO BE MORE FLEXIBLE AND EASY TO MAINTAIN.
|
|
||||||
%% -----------------------------------------------------------
|
|
||||||
\input{includes/headers.tex}
|
|
||||||
\begin{document}
|
|
||||||
\input{includes/introduction.tex}
|
|
||||||
\input{includes/google-calendar-api.tex}
|
|
||||||
\input{includes/external-tools.tex}
|
|
||||||
\input{includes/usage-scenarios.tex}
|
|
||||||
\input{includes/use-cases.tex}
|
|
||||||
\input{includes/implementation.tex}
|
|
||||||
\input{includes/unit-testing.tex}
|
|
||||||
\input{includes/conclusions.tex}
|
|
||||||
\nocite{*}
|
|
||||||
\printbibliography
|
|
||||||
\lastpageinfo
|
|
||||||
\end{document}
|
|
||||||
|
|
|
@ -1,20 +0,0 @@
|
||||||
VERSION 1.0
|
|
||||||
===========
|
|
||||||
Easy!Appointments now supports multilingual interface (English,
|
|
||||||
German, Greek, Hungarian & Portuguese)
|
|
||||||
|
|
||||||
I would like to thank Stefan Tselegidis (German), Zsolt Zala(Hungarian) and Andre Tavares (Portuguese) for their work on the translations.
|
|
||||||
|
|
||||||
|
|
||||||
Official Easy!Appointments Website:
|
|
||||||
http://easyappointments.org
|
|
||||||
|
|
||||||
Check the Google+ Community for development updates:
|
|
||||||
https://plus.google.com/communities/105333709485142846840
|
|
||||||
|
|
||||||
Visit the Support Group for any help on the project:
|
|
||||||
http://groups.google.com/group/easy-appointments
|
|
||||||
|
|
||||||
E!A Blog for news and information:
|
|
||||||
http://easyappointments.wordpress.com
|
|
||||||
|
|
7
rsc/code-doc.sh
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
#!bin/bash
|
||||||
|
|
||||||
|
# Generate PHP Documentation
|
||||||
|
|
||||||
|
|
||||||
|
# Generate JS Documentation (requires jsdoc)
|
||||||
|
|
103
rsc/db/sample-data.sql
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
-- phpMyAdmin SQL Dump
|
||||||
|
-- version 4.0.10deb1
|
||||||
|
-- http://www.phpmyadmin.net
|
||||||
|
--
|
||||||
|
-- Host: localhost
|
||||||
|
-- Generation Time: Jan 14, 2015 at 10:50 PM
|
||||||
|
-- Server version: 5.5.40-0ubuntu0.14.04.1
|
||||||
|
-- PHP Version: 5.5.9-1ubuntu4.5
|
||||||
|
|
||||||
|
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
|
||||||
|
SET time_zone = "+00:00";
|
||||||
|
|
||||||
|
|
||||||
|
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
|
||||||
|
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
|
||||||
|
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
|
||||||
|
/*!40101 SET NAMES utf8 */;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Database: `easyappointments`
|
||||||
|
--
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Dumping data for table `ea_roles`
|
||||||
|
--
|
||||||
|
|
||||||
|
INSERT INTO `ea_roles` (`id`, `name`, `slug`, `is_admin`, `appointments`, `customers`, `services`, `users`, `system_settings`, `user_settings`) VALUES
|
||||||
|
(1, 'Administrator', 'admin', 1, 15, 15, 15, 15, 15, 15),
|
||||||
|
(2, 'Provider', 'provider', 0, 15, 15, 0, 0, 0, 15),
|
||||||
|
(3, 'Customer', 'customer', 0, 0, 0, 0, 0, 0, 0),
|
||||||
|
(4, 'Secretary', 'secretary', 0, 15, 15, 0, 0, 0, 15);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Dumping data for table `ea_secretaries_providers`
|
||||||
|
--
|
||||||
|
|
||||||
|
INSERT INTO `ea_secretaries_providers` (`id_users_secretary`, `id_users_provider`) VALUES
|
||||||
|
(87, 86);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Dumping data for table `ea_services`
|
||||||
|
--
|
||||||
|
|
||||||
|
INSERT INTO `ea_services` (`id`, `name`, `duration`, `price`, `currency`, `description`, `id_service_categories`) VALUES
|
||||||
|
(1, 'Best Quick Service ', 30, 50.00, '€', 'This is the best service and it requires only 30 minutes of your time!', 1),
|
||||||
|
(2, 'Another Q. Service', 45, 60.00, '€', 'This will be the best choice for someone that wants a balance between time and money.', 1),
|
||||||
|
(3, 'Best Long Service', 180, 100.00, '€', 'This long service will examine all the aspects of your problem. Definitely the best solution!', 2),
|
||||||
|
(4, 'Ungrouped Srv.', 45, 0.00, '', 'This category is not like the rest. It can''t be grouped. ', NULL);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Dumping data for table `ea_services_providers`
|
||||||
|
--
|
||||||
|
|
||||||
|
INSERT INTO `ea_services_providers` (`id_users`, `id_services`) VALUES
|
||||||
|
(85, 1),
|
||||||
|
(85, 2),
|
||||||
|
(86, 3),
|
||||||
|
(85, 4),
|
||||||
|
(86, 4);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Dumping data for table `ea_service_categories`
|
||||||
|
--
|
||||||
|
|
||||||
|
INSERT INTO `ea_service_categories` (`id`, `name`, `description`) VALUES
|
||||||
|
(1, 'Quick Services', 'A collection of services that have small duration. '),
|
||||||
|
(2, 'Long Services', 'A collection of services that require more time. ');
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Dumping data for table `ea_settings`
|
||||||
|
--
|
||||||
|
|
||||||
|
INSERT INTO `ea_settings` (`id`, `name`, `value`) VALUES
|
||||||
|
(16, 'company_working_plan', '{"monday":{"start":"09:00","end":"18:00","breaks":[{"start":"14:30","end":"15:00"}]},"tuesday":{"start":"09:00","end":"18:00","breaks":[{"start":"14:30","end":"15:00"}]},"wednesday":{"start":"09:00","end":"18:00","breaks":[{"start":"14:30","end":"15:00"}]},"thursday":{"start":"09:00","end":"18:00","breaks":[{"start":"14:30","end":"15:00"}]},"friday":{"start":"09:00","end":"18:00","breaks":[{"start":"14:30","end":"15:00"}]},"saturday":null,"sunday":null}'),
|
||||||
|
(17, 'book_advance_timeout', '30'),
|
||||||
|
(18, 'company_name', 'ABC Company'),
|
||||||
|
(19, 'company_email', 'info@abc-company.ea'),
|
||||||
|
(20, 'company_link', 'http://www.abc-company.ea');
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Dumping data for table `ea_users`
|
||||||
|
--
|
||||||
|
|
||||||
|
INSERT INTO `ea_users` (`id`, `first_name`, `last_name`, `email`, `mobile_number`, `phone_number`, `address`, `city`, `state`, `zip_code`, `notes`, `id_roles`) VALUES
|
||||||
|
(84, 'John', 'Smith', 'info@abc-company.ea', '0123 4567890', '0123 4567891', 'Tst-Address 12', 'Tst-City', 'Tst-State', '012345', 'Test administrator record for this installation. ', 1),
|
||||||
|
(85, 'George ', 'Clayton', 'g.clayton@abc-company.ea', '0123 456 7890', '0123 456 7891', 'Tst-Address 12', 'Tst-City', 'Tst-State', '012345', 'This is one of the test providers. He will handle the quick services.', 2),
|
||||||
|
(86, 'Christina', 'Nickolson', 'c.nickolson@abc-company.ea', '0123 4567890', '0123 4567891', 'Tst-Address 12', 'Tst-City', 'Tst-State', '012345', 'This provider will handle the long services.', 2),
|
||||||
|
(87, 'Nicky', 'Rowland', 'n.rowland@abc-company.ea', '0123 4567890', '0123 4567891', 'Tst-Address 12', 'Tst-City', 'Tst-State', '012345', 'This is the only secretary of the app. She will handle the data of Christina.', 4),
|
||||||
|
(88, 'John', 'Doe', 'john.doe@abc-company.ea', NULL, '0123 4567890', 'Tst-Address 12', 'Tst-City', NULL, '012345', 'This is a test customer record.', 3);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Dumping data for table `ea_user_settings`
|
||||||
|
--
|
||||||
|
|
||||||
|
INSERT INTO `ea_user_settings` (`id_users`, `username`, `password`, `salt`, `working_plan`, `notifications`, `google_sync`, `google_token`, `google_calendar`, `sync_past_days`, `sync_future_days`) VALUES
|
||||||
|
(84, 'administrator', 'fa7fc34500cbed7c3546f8b223f10797f24ecc9ccbf0c2251c21ab965ebf19bf', 'e0a9e47fbf57babcf536e98bed783a9404b95b671cdcf9e391f68989fa3ac14f', NULL, 1, 0, NULL, NULL, 5, 5),
|
||||||
|
(85, 'g.clayton', 'a86f0c41be938c36eaedb3c4869c445fe8b7192188110f57bf86b55ac2252f05', '9b56eaa06cb0cc1c3bdce616291da4f53c2cc5d3449591bacb28099346333f05', '{"monday":{"start":"09:00","end":"18:00","breaks":[{"start":"14:30","end":"15:00"}]},"tuesday":{"start":"09:00","end":"18:00","breaks":[{"start":"14:30","end":"15:00"}]},"wednesday":{"start":"09:00","end":"18:00","breaks":[{"start":"14:30","end":"15:00"}]},"thursday":{"start":"09:00","end":"18:00","breaks":[{"start":"14:30","end":"15:00"}]},"friday":{"start":"09:00","end":"18:00","breaks":[{"start":"14:30","end":"15:00"}]},"saturday":null,"sunday":null}', 1, 0, NULL, NULL, 5, 5),
|
||||||
|
(86, 'c.nickolson', '7dcd5ed6a1cc42de678227aa8d528069761b218d181ff7ef446a49622c384782', '807349d6bacc35650205c66d664d4d414d150dec7f17dbba360752224bab73f4', '{"monday":{"start":"09:00","end":"18:00","breaks":[{"start":"14:30","end":"15:00"}]},"tuesday":{"start":"09:00","end":"18:00","breaks":[{"start":"14:30","end":"15:00"}]},"wednesday":{"start":"09:00","end":"18:00","breaks":[{"start":"14:30","end":"15:00"}]},"thursday":{"start":"09:00","end":"18:00","breaks":[{"start":"14:30","end":"15:00"}]},"friday":{"start":"09:00","end":"18:00","breaks":[{"start":"14:30","end":"15:00"}]},"saturday":null,"sunday":null}', 1, 0, NULL, NULL, 5, 5),
|
||||||
|
(87, 'n.rowland', '8cd1cc276a72f88e6d27372aecde8d87903a91fa33a6d2aceafbf2d110e4c9c2', '55b3a83cea1e3a5c4945fcb12a7621519705b3d09c4fa3408d912a832c8410a1', NULL, 1, 0, NULL, NULL, 5, 5);
|
||||||
|
|
||||||
|
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
|
||||||
|
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
|
||||||
|
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
220
rsc/db/structure.sql
Normal file
|
@ -0,0 +1,220 @@
|
||||||
|
|
||||||
|
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
|
||||||
|
SET time_zone = "+00:00";
|
||||||
|
|
||||||
|
|
||||||
|
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
|
||||||
|
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
|
||||||
|
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
|
||||||
|
/*!40101 SET NAMES utf8 */;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Database: `easyappointments`
|
||||||
|
--
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Table structure for table `ea_appointments`
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `ea_appointments` (
|
||||||
|
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`book_datetime` datetime DEFAULT NULL,
|
||||||
|
`start_datetime` datetime DEFAULT NULL,
|
||||||
|
`end_datetime` datetime DEFAULT NULL,
|
||||||
|
`notes` text,
|
||||||
|
`hash` text,
|
||||||
|
`is_unavailable` tinyint(4) DEFAULT '0',
|
||||||
|
`id_users_provider` bigint(20) unsigned DEFAULT NULL,
|
||||||
|
`id_users_customer` bigint(20) unsigned DEFAULT NULL,
|
||||||
|
`id_services` bigint(20) unsigned DEFAULT NULL,
|
||||||
|
`id_google_calendar` text,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `id_users_customer` (`id_users_customer`),
|
||||||
|
KEY `id_services` (`id_services`),
|
||||||
|
KEY `id_users_provider` (`id_users_provider`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Table structure for table `ea_roles`
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `ea_roles` (
|
||||||
|
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`name` varchar(256) DEFAULT NULL,
|
||||||
|
`slug` varchar(256) DEFAULT NULL,
|
||||||
|
`is_admin` tinyint(4) DEFAULT NULL COMMENT '0',
|
||||||
|
`appointments` int(4) DEFAULT NULL COMMENT '0',
|
||||||
|
`customers` int(4) DEFAULT NULL COMMENT '0',
|
||||||
|
`services` int(4) DEFAULT NULL COMMENT '0',
|
||||||
|
`users` int(4) DEFAULT NULL COMMENT '0',
|
||||||
|
`system_settings` int(4) DEFAULT NULL COMMENT '0',
|
||||||
|
`user_settings` int(11) DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=5 ;
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Table structure for table `ea_secretaries_providers`
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `ea_secretaries_providers` (
|
||||||
|
`id_users_secretary` bigint(20) unsigned NOT NULL,
|
||||||
|
`id_users_provider` bigint(20) unsigned NOT NULL,
|
||||||
|
PRIMARY KEY (`id_users_secretary`,`id_users_provider`),
|
||||||
|
KEY `fk_ea_secretaries_providers_1` (`id_users_secretary`),
|
||||||
|
KEY `fk_ea_secretaries_providers_2` (`id_users_provider`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Table structure for table `ea_services`
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `ea_services` (
|
||||||
|
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`name` varchar(256) DEFAULT NULL,
|
||||||
|
`duration` int(11) DEFAULT NULL,
|
||||||
|
`price` decimal(10,2) DEFAULT NULL,
|
||||||
|
`currency` varchar(32) DEFAULT NULL,
|
||||||
|
`description` text,
|
||||||
|
`id_service_categories` bigint(20) unsigned DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `id_service_categories` (`id_service_categories`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Table structure for table `ea_services_providers`
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `ea_services_providers` (
|
||||||
|
`id_users` bigint(20) unsigned NOT NULL,
|
||||||
|
`id_services` bigint(20) unsigned NOT NULL,
|
||||||
|
PRIMARY KEY (`id_users`,`id_services`),
|
||||||
|
KEY `id_services` (`id_services`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Table structure for table `ea_service_categories`
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `ea_service_categories` (
|
||||||
|
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`name` varchar(256) DEFAULT NULL,
|
||||||
|
`description` text,
|
||||||
|
PRIMARY KEY (`id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Table structure for table `ea_settings`
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `ea_settings` (
|
||||||
|
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`name` varchar(512) DEFAULT NULL,
|
||||||
|
`value` longtext,
|
||||||
|
PRIMARY KEY (`id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=21 ;
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Table structure for table `ea_users`
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `ea_users` (
|
||||||
|
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`first_name` varchar(256) DEFAULT NULL,
|
||||||
|
`last_name` varchar(512) DEFAULT NULL,
|
||||||
|
`email` varchar(512) DEFAULT NULL,
|
||||||
|
`mobile_number` varchar(128) DEFAULT NULL,
|
||||||
|
`phone_number` varchar(128) DEFAULT NULL,
|
||||||
|
`address` varchar(256) DEFAULT NULL,
|
||||||
|
`city` varchar(256) DEFAULT NULL,
|
||||||
|
`state` varchar(128) DEFAULT NULL,
|
||||||
|
`zip_code` varchar(64) DEFAULT NULL,
|
||||||
|
`notes` text,
|
||||||
|
`id_roles` bigint(20) unsigned NOT NULL,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `id_roles` (`id_roles`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=85 ;
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Table structure for table `ea_user_settings`
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `ea_user_settings` (
|
||||||
|
`id_users` bigint(20) unsigned NOT NULL,
|
||||||
|
`username` varchar(256) DEFAULT NULL,
|
||||||
|
`password` varchar(512) DEFAULT NULL,
|
||||||
|
`salt` varchar(512) DEFAULT NULL,
|
||||||
|
`working_plan` text,
|
||||||
|
`notifications` tinyint(4) DEFAULT '0',
|
||||||
|
`google_sync` tinyint(4) DEFAULT '0',
|
||||||
|
`google_token` text,
|
||||||
|
`google_calendar` varchar(128) DEFAULT NULL,
|
||||||
|
`sync_past_days` int(11) DEFAULT '5',
|
||||||
|
`sync_future_days` int(11) DEFAULT '5',
|
||||||
|
PRIMARY KEY (`id_users`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Constraints for dumped tables
|
||||||
|
--
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Constraints for table `ea_appointments`
|
||||||
|
--
|
||||||
|
ALTER TABLE `ea_appointments`
|
||||||
|
ADD CONSTRAINT `ea_appointments_ibfk_2` FOREIGN KEY (`id_users_customer`) REFERENCES `ea_users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||||
|
ADD CONSTRAINT `ea_appointments_ibfk_3` FOREIGN KEY (`id_services`) REFERENCES `ea_services` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||||
|
ADD CONSTRAINT `ea_appointments_ibfk_4` FOREIGN KEY (`id_users_provider`) REFERENCES `ea_users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Constraints for table `ea_secretaries_providers`
|
||||||
|
--
|
||||||
|
ALTER TABLE `ea_secretaries_providers`
|
||||||
|
ADD CONSTRAINT `fk_ea_secretaries_providers_1` FOREIGN KEY (`id_users_secretary`) REFERENCES `ea_users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||||
|
ADD CONSTRAINT `fk_ea_secretaries_providers_2` FOREIGN KEY (`id_users_provider`) REFERENCES `ea_users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Constraints for table `ea_services`
|
||||||
|
--
|
||||||
|
ALTER TABLE `ea_services`
|
||||||
|
ADD CONSTRAINT `ea_services_ibfk_1` FOREIGN KEY (`id_service_categories`) REFERENCES `ea_service_categories` (`id`) ON DELETE SET NULL ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Constraints for table `ea_services_providers`
|
||||||
|
--
|
||||||
|
ALTER TABLE `ea_services_providers`
|
||||||
|
ADD CONSTRAINT `ea_services_providers_ibfk_1` FOREIGN KEY (`id_users`) REFERENCES `ea_users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||||
|
ADD CONSTRAINT `ea_services_providers_ibfk_2` FOREIGN KEY (`id_services`) REFERENCES `ea_services` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Constraints for table `ea_users`
|
||||||
|
--
|
||||||
|
ALTER TABLE `ea_users`
|
||||||
|
ADD CONSTRAINT `ea_users_ibfk_1` FOREIGN KEY (`id_roles`) REFERENCES `ea_roles` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Constraints for table `ea_user_settings`
|
||||||
|
--
|
||||||
|
ALTER TABLE `ea_user_settings`
|
||||||
|
ADD CONSTRAINT `ea_user_settings_ibfk_1` FOREIGN KEY (`id_users`) REFERENCES `ea_users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
|
||||||
|
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
|
||||||
|
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
Before Width: | Height: | Size: 7 KiB After Width: | Height: | Size: 7 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 41 KiB |
|
@ -1,53 +0,0 @@
|
||||||
Apache License
|
|
||||||
|
|
||||||
Version 2.0, January 2004
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/
|
|
||||||
|
|
||||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
||||||
|
|
||||||
1. Definitions.
|
|
||||||
|
|
||||||
&quot;License&quot; shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
|
|
||||||
|
|
||||||
&quot;Licensor&quot; shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
|
|
||||||
|
|
||||||
&quot;Legal Entity&quot; shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, &quot;control&quot; means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
|
|
||||||
|
|
||||||
&quot;You&quot; (or &quot;Your&quot;) shall mean an individual or Legal Entity exercising permissions granted by this License.
|
|
||||||
|
|
||||||
&quot;Source&quot; form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
|
|
||||||
|
|
||||||
&quot;Object&quot; form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
|
|
||||||
|
|
||||||
&quot;Work&quot; shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
|
|
||||||
|
|
||||||
&quot;Derivative Works&quot; shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
|
|
||||||
|
|
||||||
&quot;Contribution&quot; shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, &quot;submitted&quot; means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as &quot;Not a Contribution.&quot;
|
|
||||||
|
|
||||||
&quot;Contributor&quot; shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
|
|
||||||
|
|
||||||
2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
|
|
||||||
|
|
||||||
3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
|
|
||||||
|
|
||||||
4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
|
|
||||||
|
|
||||||
You must give any other recipients of the Work or Derivative Works a copy of this License; and
|
|
||||||
|
|
||||||
You must cause any modified files to carry prominent notices stating that You changed the files; and
|
|
||||||
|
|
||||||
You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
|
|
||||||
|
|
||||||
If the Work includes a &quot;NOTICE&quot; text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
|
|
||||||
|
|
||||||
5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
|
|
||||||
|
|
||||||
6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
|
|
||||||
|
|
||||||
7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an &quot;AS IS&quot; BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
|
|
||||||
|
|
||||||
8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
|
|
||||||
|
|
||||||
9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
|
|
10
rsc/package.sh
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
#!bin/bash
|
||||||
|
|
||||||
|
|
||||||
|
# Create Build Directory
|
||||||
|
|
||||||
|
|
||||||
|
# Minify and Concatenate Assets Code
|
||||||
|
|
||||||
|
|
||||||
|
# Zip Folder
|
|
@ -1,335 +0,0 @@
|
||||||
/*
|
|
||||||
mustache.js — Logic-less templates in JavaScript
|
|
||||||
|
|
||||||
See http://mustache.github.com/ for more info.
|
|
||||||
*/
|
|
||||||
|
|
||||||
var Mustache = function() {
|
|
||||||
var Renderer = function() {};
|
|
||||||
|
|
||||||
Renderer.prototype = {
|
|
||||||
otag: "{{",
|
|
||||||
ctag: "}}",
|
|
||||||
pragmas: {},
|
|
||||||
buffer: [],
|
|
||||||
pragmas_implemented: {
|
|
||||||
"IMPLICIT-ITERATOR": true,
|
|
||||||
"ARRAY-ORDINALS": true // define #first? and #last? when looping arrays
|
|
||||||
},
|
|
||||||
context: {},
|
|
||||||
|
|
||||||
render: function(template, context, partials, in_recursion) {
|
|
||||||
// reset buffer & set context
|
|
||||||
if(!in_recursion) {
|
|
||||||
this.context = context;
|
|
||||||
this.buffer = []; // TODO: make this non-lazy
|
|
||||||
}
|
|
||||||
|
|
||||||
// fail fast
|
|
||||||
if(!this.includes("", template)) {
|
|
||||||
if(in_recursion) {
|
|
||||||
return template;
|
|
||||||
} else {
|
|
||||||
this.send(template);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template = this.render_pragmas(template);
|
|
||||||
var html = this.render_section(template, context, partials);
|
|
||||||
if(in_recursion) {
|
|
||||||
return this.render_tags(html, context, partials, in_recursion);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.render_tags(html, context, partials, in_recursion);
|
|
||||||
},
|
|
||||||
|
|
||||||
/*
|
|
||||||
Sends parsed lines
|
|
||||||
*/
|
|
||||||
send: function(line) {
|
|
||||||
if(line != "") {
|
|
||||||
this.buffer.push(line);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/*
|
|
||||||
Looks for %PRAGMAS
|
|
||||||
*/
|
|
||||||
render_pragmas: function(template) {
|
|
||||||
// no pragmas
|
|
||||||
if(!this.includes("%", template)) {
|
|
||||||
return template;
|
|
||||||
}
|
|
||||||
|
|
||||||
var that = this;
|
|
||||||
var regex = new RegExp(this.otag + "%([\\w-]+) ?([\\w]+=[\\w]+)?" +
|
|
||||||
this.ctag);
|
|
||||||
return template.replace(regex, function(match, pragma, options) {
|
|
||||||
if(!that.pragmas_implemented[pragma]) {
|
|
||||||
throw({message:
|
|
||||||
"This implementation of mustache doesn't understand the '" +
|
|
||||||
pragma + "' pragma"});
|
|
||||||
}
|
|
||||||
that.pragmas[pragma] = {};
|
|
||||||
if(options) {
|
|
||||||
var opts = options.split("=");
|
|
||||||
that.pragmas[pragma][opts[0]] = opts[1];
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
// ignore unknown pragmas silently
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
/*
|
|
||||||
Tries to find a partial in the curent scope and render it
|
|
||||||
*/
|
|
||||||
render_partial: function(name, context, partials) {
|
|
||||||
name = this.trim(name);
|
|
||||||
if(!partials || partials[name] === undefined) {
|
|
||||||
throw({message: "unknown_partial '" + name + "'"});
|
|
||||||
}
|
|
||||||
if(typeof(context[name]) != "object") {
|
|
||||||
return this.render(partials[name], context, partials, true);
|
|
||||||
}
|
|
||||||
return this.render(partials[name], context[name], partials, true);
|
|
||||||
},
|
|
||||||
|
|
||||||
/*
|
|
||||||
Renders inverted (^) and normal (#) sections
|
|
||||||
*/
|
|
||||||
render_section: function(template, context, partials) {
|
|
||||||
if(!this.includes("#", template) && !this.includes("^", template)) {
|
|
||||||
return template;
|
|
||||||
}
|
|
||||||
|
|
||||||
var that = this;
|
|
||||||
// CSW - Added "+?" so it finds the tighest bound, not the widest
|
|
||||||
var regex = new RegExp(this.otag + "(\\^|\\#)\\s*(.+)\\s*" + this.ctag +
|
|
||||||
"\n*([\\s\\S]+?)" + this.otag + "\\/\\s*\\2\\s*" + this.ctag +
|
|
||||||
"\\s*", "mg");
|
|
||||||
|
|
||||||
// for each {{#foo}}{{/foo}} section do...
|
|
||||||
return template.replace(regex, function(match, type, name, content) {
|
|
||||||
var value = that.find(name, context);
|
|
||||||
if(type == "^") { // inverted section
|
|
||||||
if(!value || that.is_array(value) && value.length === 0) {
|
|
||||||
// false or empty list, render it
|
|
||||||
return that.render(content, context, partials, true);
|
|
||||||
} else {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
} else if(type == "#") { // normal section
|
|
||||||
if(that.is_array(value)) { // Enumerable, Let's loop!
|
|
||||||
var len = value.length;
|
|
||||||
return value.map(function(row, i) {
|
|
||||||
return that.render(content, that.create_context(row, {first: i === 0, last: i === len-1}),
|
|
||||||
partials, true);
|
|
||||||
}).join("");
|
|
||||||
} else if(that.is_object(value)) { // Object, Use it as subcontext!
|
|
||||||
return that.render(content, that.create_context(value),
|
|
||||||
partials, true);
|
|
||||||
} else if(typeof value === "function") {
|
|
||||||
// higher order section
|
|
||||||
return value.call(context, content, function(text) {
|
|
||||||
return that.render(text, context, partials, true);
|
|
||||||
});
|
|
||||||
} else if(value) { // boolean section
|
|
||||||
return that.render(content, context, partials, true);
|
|
||||||
} else {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
/*
|
|
||||||
Replace {{foo}} and friends with values from our view
|
|
||||||
*/
|
|
||||||
render_tags: function(template, context, partials, in_recursion) {
|
|
||||||
// tit for tat
|
|
||||||
var that = this;
|
|
||||||
|
|
||||||
var new_regex = function() {
|
|
||||||
return new RegExp(that.otag + "(=|!|>|\\{|%)?([^\\/#\\^]+?)\\1?" +
|
|
||||||
that.ctag + "+", "g");
|
|
||||||
};
|
|
||||||
|
|
||||||
var regex = new_regex();
|
|
||||||
var tag_replace_callback = function(match, operator, name) {
|
|
||||||
switch(operator) {
|
|
||||||
case "!": // ignore comments
|
|
||||||
return "";
|
|
||||||
case "=": // set new delimiters, rebuild the replace regexp
|
|
||||||
that.set_delimiters(name);
|
|
||||||
regex = new_regex();
|
|
||||||
return "";
|
|
||||||
case ">": // render partial
|
|
||||||
return that.render_partial(name, context, partials);
|
|
||||||
case "{": // the triple mustache is unescaped
|
|
||||||
return that.find(name, context);
|
|
||||||
default: // escape the value
|
|
||||||
return that.escape(that.find(name, context));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
var lines = template.split("\n");
|
|
||||||
for(var i = 0; i < lines.length; i++) {
|
|
||||||
lines[i] = lines[i].replace(regex, tag_replace_callback, this);
|
|
||||||
if(!in_recursion) {
|
|
||||||
this.send(lines[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(in_recursion) {
|
|
||||||
return lines.join("\n");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
set_delimiters: function(delimiters) {
|
|
||||||
var dels = delimiters.split(" ");
|
|
||||||
this.otag = this.escape_regex(dels[0]);
|
|
||||||
this.ctag = this.escape_regex(dels[1]);
|
|
||||||
},
|
|
||||||
|
|
||||||
escape_regex: function(text) {
|
|
||||||
// thank you Simon Willison
|
|
||||||
if(!arguments.callee.sRE) {
|
|
||||||
var specials = [
|
|
||||||
'/', '.', '*', '+', '?', '|',
|
|
||||||
'(', ')', '[', ']', '{', '}', '\\'
|
|
||||||
];
|
|
||||||
arguments.callee.sRE = new RegExp(
|
|
||||||
'(\\' + specials.join('|\\') + ')', 'g'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return text.replace(arguments.callee.sRE, '\\$1');
|
|
||||||
},
|
|
||||||
|
|
||||||
/*
|
|
||||||
find `name` in current `context`. That is find me a value
|
|
||||||
from the view object
|
|
||||||
*/
|
|
||||||
find: function(name, context) {
|
|
||||||
name = this.trim(name);
|
|
||||||
|
|
||||||
// Checks whether a value is thruthy or false or 0
|
|
||||||
function is_kinda_truthy(bool) {
|
|
||||||
return bool === false || bool === 0 || bool;
|
|
||||||
}
|
|
||||||
|
|
||||||
var value;
|
|
||||||
if(is_kinda_truthy(context[name])) {
|
|
||||||
value = context[name];
|
|
||||||
} else if(is_kinda_truthy(this.context[name])) {
|
|
||||||
value = this.context[name];
|
|
||||||
}
|
|
||||||
|
|
||||||
if(typeof value === "function") {
|
|
||||||
return value.apply(context);
|
|
||||||
}
|
|
||||||
if(value !== undefined) {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
// silently ignore unkown variables
|
|
||||||
return "";
|
|
||||||
},
|
|
||||||
|
|
||||||
// Utility methods
|
|
||||||
|
|
||||||
/* includes tag */
|
|
||||||
includes: function(needle, haystack) {
|
|
||||||
return haystack.indexOf(this.otag + needle) != -1;
|
|
||||||
},
|
|
||||||
|
|
||||||
/*
|
|
||||||
Does away with nasty characters
|
|
||||||
*/
|
|
||||||
escape: function(s) {
|
|
||||||
s = String(s === null ? "" : s);
|
|
||||||
return s.replace(/&(?!\w+;)|["'<>\\]/g, function(s) {
|
|
||||||
switch(s) {
|
|
||||||
case "&": return "&";
|
|
||||||
case "\\": return "\\\\";
|
|
||||||
case '"': return '"';
|
|
||||||
case "'": return ''';
|
|
||||||
case "<": return "<";
|
|
||||||
case ">": return ">";
|
|
||||||
default: return s;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
// by @langalex, support for arrays of strings
|
|
||||||
create_context: function(_context, opts) {
|
|
||||||
if(this.is_object(_context)) {
|
|
||||||
if (this.pragmas["ARRAY-ORDINALS"] && opts) {
|
|
||||||
_context['first?'] = opts.first || false;
|
|
||||||
_context['last?'] = opts.last || false;
|
|
||||||
}
|
|
||||||
return _context;
|
|
||||||
} else {
|
|
||||||
var iterator = ".";
|
|
||||||
if(this.pragmas["IMPLICIT-ITERATOR"]) {
|
|
||||||
iterator = this.pragmas["IMPLICIT-ITERATOR"].iterator;
|
|
||||||
}
|
|
||||||
var ctx = {};
|
|
||||||
ctx[iterator] = _context;
|
|
||||||
if (this.pragmas["ARRAY-ORDINALS"] && opts){
|
|
||||||
ctx['first?'] = opts.first || false;
|
|
||||||
ctx['last?'] = opts.last || false;
|
|
||||||
}
|
|
||||||
return ctx;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
is_object: function(a) {
|
|
||||||
return a && typeof a == "object";
|
|
||||||
},
|
|
||||||
|
|
||||||
is_array: function(a) {
|
|
||||||
return Object.prototype.toString.call(a) === '[object Array]';
|
|
||||||
},
|
|
||||||
|
|
||||||
/*
|
|
||||||
Gets rid of leading and trailing whitespace
|
|
||||||
*/
|
|
||||||
trim: function(s) {
|
|
||||||
return s.replace(/^\s*|\s*$/g, "");
|
|
||||||
},
|
|
||||||
|
|
||||||
/*
|
|
||||||
Why, why, why? Because IE. Cry, cry cry.
|
|
||||||
*/
|
|
||||||
map: function(array, fn) {
|
|
||||||
if (typeof array.map == "function") {
|
|
||||||
return array.map(fn);
|
|
||||||
} else {
|
|
||||||
var r = [];
|
|
||||||
var l = array.length;
|
|
||||||
for(var i = 0; i < l; i++) {
|
|
||||||
r.push(fn(array[i]));
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return({
|
|
||||||
name: "mustache.js",
|
|
||||||
version: "0.3.1-dev",
|
|
||||||
|
|
||||||
/*
|
|
||||||
Turns a template and view into HTML
|
|
||||||
*/
|
|
||||||
to_html: function(template, view, partials, send_fun) {
|
|
||||||
var renderer = new Renderer();
|
|
||||||
if(send_fun) {
|
|
||||||
renderer.send = send_fun;
|
|
||||||
}
|
|
||||||
renderer.render(template, view, partials);
|
|
||||||
if(!send_fun) {
|
|
||||||
return renderer.buffer.join("\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}();
|
|
|
@ -1,46 +0,0 @@
|
||||||
{
|
|
||||||
"name": "{{appname}}",
|
|
||||||
"version": "{{appversion}}",
|
|
||||||
"revision": "{{timestamp}}",
|
|
||||||
"description": "An API documentation generator for JavaScript.",
|
|
||||||
"keywords": [ "documentation", "javascript" ],
|
|
||||||
"licenses": [
|
|
||||||
{
|
|
||||||
"type": "Apache 2.0",
|
|
||||||
"url": "http://www.apache.org/licenses/LICENSE-2.0"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"repositories": [
|
|
||||||
{
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/jsdoc3/jsdoc"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"dependencies": {
|
|
||||||
"async": "0.1.22",
|
|
||||||
"catharsis": "0.5.6",
|
|
||||||
"crypto-browserify": "git+https://github.com/dominictarr/crypto-browserify.git#95c5d505",
|
|
||||||
"js2xmlparser": "0.1.0",
|
|
||||||
"jshint": "0.9.1",
|
|
||||||
"markdown": "git+https://github.com/jsdoc3/markdown-js.git",
|
|
||||||
"marked": "0.2.8",
|
|
||||||
"taffydb": "git+https://github.com/hegemonic/taffydb.git",
|
|
||||||
"underscore": "1.4.2",
|
|
||||||
"wrench": "1.3.9"
|
|
||||||
},
|
|
||||||
"bin": "./nodejs/bin/jsdoc",
|
|
||||||
"bugs": "https://github.com/jsdoc3/jsdoc/issues",
|
|
||||||
"author": {
|
|
||||||
"name": "Michael Mathews",
|
|
||||||
"email": "micmath@gmail.com"
|
|
||||||
},
|
|
||||||
"contributors": [
|
|
||||||
{
|
|
||||||
"url": "https://github.com/jsdoc3/jsdoc/graphs/contributors"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"maintainers": {
|
|
||||||
"name": "Jeff Williams",
|
|
||||||
"email": "jeffrey.l.williams@gmail.com"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,82 +0,0 @@
|
||||||
/*global desc: true, fail: true, Mustache: true, task: true */
|
|
||||||
// see: https://github.com/mde/jake
|
|
||||||
|
|
||||||
desc('Updating package.json revision.');
|
|
||||||
task('default', [], function(params) {
|
|
||||||
/*jshint evil: true */
|
|
||||||
var fs = require('fs');
|
|
||||||
|
|
||||||
// import the Mustache template tool
|
|
||||||
eval(fs.readFileSync('Jake/lib/mustache.js', 'utf8'));
|
|
||||||
|
|
||||||
var templates = {
|
|
||||||
packagejson : fs.readFileSync('Jake/templates/package.json.tmpl', 'utf8')
|
|
||||||
};
|
|
||||||
|
|
||||||
var metadata = {
|
|
||||||
appname : 'jsdoc',
|
|
||||||
appversion : '3.2.0-dev',
|
|
||||||
timestamp : '' + new Date().getTime()
|
|
||||||
};
|
|
||||||
|
|
||||||
var outdir = './';
|
|
||||||
|
|
||||||
var rendered = Mustache.to_html(templates.packagejson, metadata);
|
|
||||||
|
|
||||||
fs.writeFileSync(outdir + 'package.json', rendered, 'utf8');
|
|
||||||
|
|
||||||
process.exit(0);
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
desc('Installs a plugin/template.');
|
|
||||||
task('install', [], function(loc) {
|
|
||||||
var fs = require('fs'),
|
|
||||||
util = require('util'),
|
|
||||||
path = require('path'),
|
|
||||||
wrench = require('wrench');
|
|
||||||
|
|
||||||
if(!loc) {
|
|
||||||
fail("You must specify the location of the plugin/template.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!fs.existsSync(loc)) {
|
|
||||||
fail("plugin/template location [" + loc + "] is not valid.");
|
|
||||||
}
|
|
||||||
|
|
||||||
var pluginLoc = path.join(loc, "plugins"),
|
|
||||||
templateLoc = path.join(loc, "templates"),
|
|
||||||
jsdocLoc = process.cwd(),
|
|
||||||
name,
|
|
||||||
config;
|
|
||||||
|
|
||||||
//First the plugin
|
|
||||||
if(fs.existsSync(pluginLoc)) {
|
|
||||||
//copy it over
|
|
||||||
wrench.copyDirSyncRecursive(pluginLoc, path.join(jsdocLoc, "plugins"), {
|
|
||||||
preserve : true
|
|
||||||
});
|
|
||||||
//find out what it's called
|
|
||||||
name = fs.readdirSync(pluginLoc)[0].replace(".js", "");
|
|
||||||
//And finally edit the conf.json
|
|
||||||
try {
|
|
||||||
config = JSON.parse(fs.readFileSync(path.join(jsdocLoc, 'conf.json'), 'utf8'));
|
|
||||||
if(config.plugins.indexOf('plugins/' + name) == -1) {
|
|
||||||
config.plugins.push('plugins/' + name);
|
|
||||||
fs.writeFileSync(path.join(jsdocLoc, 'conf.json'), JSON.stringify(config, null, " "), 'utf8');
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
fail("Could not edit the conf.json file: " + e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Then the template
|
|
||||||
if(fs.existsSync(templateLoc)) {
|
|
||||||
wrench.copyDirSyncRecursive(templateLoc, path.join(jsdocLoc, "templates"), {
|
|
||||||
preserve : true
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
process.exit(0);
|
|
||||||
|
|
||||||
});
|
|
|
@ -1,344 +0,0 @@
|
||||||
# License #
|
|
||||||
|
|
||||||
JSDoc 3 is free software, licensed under the Apache License, Version 2.0 (the
|
|
||||||
"License"). Commercial and non-commercial use are permitted in compliance with
|
|
||||||
the License.
|
|
||||||
|
|
||||||
Copyright (c) 2011-2012 Michael Mathews <micmath@gmail.com>
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
You may obtain a copy of the License at:
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
In addition, a copy of the License is included with this distribution.
|
|
||||||
|
|
||||||
As stated in Section 7, "Disclaimer of Warranty," of the License:
|
|
||||||
|
|
||||||
> Licensor provides the Work (and each Contributor provides its Contributions)
|
|
||||||
> on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
|
|
||||||
> express or implied, including, without limitation, any warranties or
|
|
||||||
> conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
||||||
> PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
||||||
> appropriateness of using or redistributing the Work and assume any risks
|
|
||||||
> associated with Your exercise of mpermissions under this License.
|
|
||||||
|
|
||||||
The source code for JSDoc 3 is available at:
|
|
||||||
https://github.com/jsdoc3/jsdoc
|
|
||||||
|
|
||||||
|
|
||||||
# Third-Party Software #
|
|
||||||
|
|
||||||
JSDoc 3 includes or depends upon the following third-party software, either in
|
|
||||||
whole or in part. Each third-party software package is provided under its own
|
|
||||||
license.
|
|
||||||
|
|
||||||
## MIT License ##
|
|
||||||
|
|
||||||
Several of the following software packages are distributed under the MIT
|
|
||||||
license, which is reproduced below:
|
|
||||||
|
|
||||||
> Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
> of this software and associated documentation files (the "Software"), to deal
|
|
||||||
> in the Software without restriction, including without limitation the rights
|
|
||||||
> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
> copies of the Software, and to permit persons to whom the Software is
|
|
||||||
> furnished to do so, subject to the following conditions:
|
|
||||||
>
|
|
||||||
> The above copyright notice and this permission notice shall be included in all
|
|
||||||
> copies or substantial portions of the Software.
|
|
||||||
>
|
|
||||||
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
> SOFTWARE.
|
|
||||||
|
|
||||||
|
|
||||||
## Async.js ##
|
|
||||||
|
|
||||||
Async.js is distributed under the MIT license, which is reproduced above.
|
|
||||||
|
|
||||||
Copyright (c) 2010 Caolan McMahon.
|
|
||||||
|
|
||||||
The source code for Async.js is available at:
|
|
||||||
https://github.com/caolan/async
|
|
||||||
|
|
||||||
|
|
||||||
## Catharsis ##
|
|
||||||
|
|
||||||
Catharsis is distributed under the MIT license, which is reproduced above.
|
|
||||||
|
|
||||||
Copyright (c) 2012-2013 Jeff Williams.
|
|
||||||
|
|
||||||
The source code for Catharsis is available at:
|
|
||||||
https://github.com/hegemonic/catharsis
|
|
||||||
|
|
||||||
|
|
||||||
## crypto-browserify ##
|
|
||||||
|
|
||||||
License information for crypto-browserify is not available. It is assumed that
|
|
||||||
the package is distributed under the MIT license or a similar open source
|
|
||||||
license.
|
|
||||||
|
|
||||||
The source code for crypto-browserify is available at:
|
|
||||||
https://github.com/dominictarr/crypto-browserify
|
|
||||||
|
|
||||||
|
|
||||||
## github-flavored-markdown ##
|
|
||||||
|
|
||||||
github-flavored-markdown is distributed under the BSD 3-clause license:
|
|
||||||
|
|
||||||
> Copyright (c) 2007, John Fraser <http://www.attacklab.net/> All rights
|
|
||||||
> reserved.
|
|
||||||
>
|
|
||||||
> Original Markdown copyright (c) 2004, John Gruber <http://daringfireball.net/>
|
|
||||||
> All rights reserved.
|
|
||||||
>
|
|
||||||
> Redistribution and use in source and binary forms, with or without
|
|
||||||
> modification, are permitted provided that the following conditions are met:
|
|
||||||
>
|
|
||||||
> - Redistributions of source code must retain the above copyright notice,
|
|
||||||
> this list of conditions and the following disclaimer.
|
|
||||||
>
|
|
||||||
> - Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
> this list of conditions and the following disclaimer in the documentation
|
|
||||||
> and/or other materials provided with the distribution.
|
|
||||||
|
|
||||||
> - Neither the name "Markdown" nor the names of its contributors may be used
|
|
||||||
> to endorse or promote products derived from this software without specific
|
|
||||||
> prior written permission.
|
|
||||||
>
|
|
||||||
> This software is provided by the copyright holders and contributors "as is"
|
|
||||||
> and any express or implied warranties, including, but not limited to, the
|
|
||||||
> implied warranties of merchantability and fitness for a particular purpose are
|
|
||||||
> disclaimed. In no event shall the copyright owner or contributors be liable
|
|
||||||
> for any direct, indirect, incidental, special, exemplary, or consequential
|
|
||||||
> damages (including, but not limited to, procurement of substitute goods or
|
|
||||||
> services; loss of use, data, or profits; or business interruption) however
|
|
||||||
> caused and on any theory of liability, whether in contract, strict liability,
|
|
||||||
> or tort (including negligence or otherwise) arising in any way out of the use
|
|
||||||
> of this software, even if advised of the possibility of such damage.
|
|
||||||
|
|
||||||
The source code for github-flavored-markdown is available at:
|
|
||||||
https://github.com/hegemonic/github-flavored-markdown
|
|
||||||
|
|
||||||
|
|
||||||
## Google Code Prettify ##
|
|
||||||
|
|
||||||
Google Code Prettify is distributed under the Apache License 2.0, which is
|
|
||||||
included with this package.
|
|
||||||
|
|
||||||
Copyright (c) 2006 Google Inc.
|
|
||||||
|
|
||||||
The source code for Google Code Prettify is available at:
|
|
||||||
https://code.google.com/p/google-code-prettify/
|
|
||||||
|
|
||||||
|
|
||||||
## Jasmine ##
|
|
||||||
|
|
||||||
Jasmine is distributed under the MIT license, which is reproduced above.
|
|
||||||
|
|
||||||
Copyright (c) 2008-2011 Pivotal Labs.
|
|
||||||
|
|
||||||
The source code for Jasmine is available at:
|
|
||||||
https://github.com/pivotal/jasmine
|
|
||||||
|
|
||||||
|
|
||||||
## jasmine-node ##
|
|
||||||
|
|
||||||
jasmine-node is distributed under the MIT license, which is reproduced above.
|
|
||||||
|
|
||||||
Copyright (c) 2010 Adam Abrons and Misko Hevery (http://getangular.com).
|
|
||||||
|
|
||||||
The source code for jasmine-node is available at:
|
|
||||||
https://github.com/mhevery/jasmine-node
|
|
||||||
|
|
||||||
|
|
||||||
## js2xmlparser ##
|
|
||||||
|
|
||||||
js2xmlparser is distributed under the MIT license, which is reproduced above.
|
|
||||||
|
|
||||||
Copyright (c) 2012 Michael Kourlas.
|
|
||||||
|
|
||||||
The source code for js2xmlparser is available at:
|
|
||||||
https://github.com/michaelkourlas/node-js2xmlparser
|
|
||||||
|
|
||||||
|
|
||||||
## JSHint ##
|
|
||||||
|
|
||||||
JSHint is distributed under the MIT license, which is reproduced above.
|
|
||||||
|
|
||||||
Portions of JSHint are derived from JSLint, which is distributed under a
|
|
||||||
modified MIT license:
|
|
||||||
|
|
||||||
> Copyright (c) 2002 Douglas Crockford (www.JSLint.com)
|
|
||||||
>
|
|
||||||
> Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
> of this software and associated documentation files (the "Software"), to deal
|
|
||||||
> in the Software without restriction, including without limitation the rights
|
|
||||||
> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
> copies of the Software, and to permit persons to whom the Software is
|
|
||||||
> furnished to do so, subject to the following conditions:
|
|
||||||
>
|
|
||||||
> The above copyright notice and this permission notice shall be included in all
|
|
||||||
> copies or substantial portions of the Software.
|
|
||||||
>
|
|
||||||
> The Software shall be used for Good, not Evil.
|
|
||||||
>
|
|
||||||
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
> SOFTWARE.
|
|
||||||
|
|
||||||
The source code for JSHint is available at:
|
|
||||||
https://github.com/jshint/jshint
|
|
||||||
|
|
||||||
|
|
||||||
## markdown-js ##
|
|
||||||
|
|
||||||
markdown-js is distributed under the MIT license, which is reproduced above.
|
|
||||||
|
|
||||||
Copyright (c) 2009-2010 Dominic Baggott. Copyright (c) 2009-2010 Ash Berlin.
|
|
||||||
Copyright (c) 2011 Christoph Dorn <christoph@christophdorn.com>
|
|
||||||
(http://www.christophdorn.com).
|
|
||||||
|
|
||||||
The source code for markdown-js is available at:
|
|
||||||
https://github.com/evilstreak/markdown-js
|
|
||||||
|
|
||||||
|
|
||||||
## Node.js ##
|
|
||||||
|
|
||||||
Portions of the Node.js source code are incorporated into the following files:
|
|
||||||
|
|
||||||
- `rhino/fs.js`
|
|
||||||
- `rhino/path.js`
|
|
||||||
- `rhino/querystring.js`
|
|
||||||
- `rhino/util.js`
|
|
||||||
|
|
||||||
Node.js is distributed under the MIT license, which is reproduced above.
|
|
||||||
|
|
||||||
Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
|
||||||
|
|
||||||
The source code for Node.js is available at:
|
|
||||||
https://github.com/joyent/node
|
|
||||||
|
|
||||||
|
|
||||||
## node-browserify ##
|
|
||||||
|
|
||||||
Portions of the node-browserify source code are incorporated into the following
|
|
||||||
files:
|
|
||||||
|
|
||||||
- `rhino/events.js`
|
|
||||||
|
|
||||||
node-browserify is distributed under the MIT license, which is reproduced above.
|
|
||||||
|
|
||||||
The source code for node-browserify is available at:
|
|
||||||
https://github.com/substack/node-browserify
|
|
||||||
|
|
||||||
|
|
||||||
## TaffyDB ##
|
|
||||||
|
|
||||||
TaffyDB is distributed under a modified BSD license:
|
|
||||||
|
|
||||||
> All rights reserved.
|
|
||||||
>
|
|
||||||
> Redistribution and use of this software in source and binary forms, with or
|
|
||||||
> without modification, are permitted provided that the following condition is
|
|
||||||
> met:
|
|
||||||
>
|
|
||||||
> Redistributions of source code must retain the above copyright notice, this
|
|
||||||
> list of conditions and the following disclaimer.
|
|
||||||
>
|
|
||||||
> THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
> AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
> IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
> ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
||||||
> LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
||||||
> CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
||||||
> SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
> INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
> CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
||||||
> ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
||||||
> POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
The source code for TaffyDB is available at:
|
|
||||||
https://github.com/hegemonic/taffydb
|
|
||||||
|
|
||||||
|
|
||||||
## Tomorrow Theme for Google Code Prettify ##
|
|
||||||
|
|
||||||
License information for the Tomorrow Theme for Google Code Prettify is not
|
|
||||||
available. It is assumed that the package is distributed under an open source
|
|
||||||
license that is compatible with the Apache License 2.0.
|
|
||||||
|
|
||||||
Copyright (c) Yoshihide Jimbo.
|
|
||||||
|
|
||||||
The source code for the Tomorrow Theme is available at:
|
|
||||||
https://github.com/jmblog/color-themes-for-google-code-prettify
|
|
||||||
|
|
||||||
|
|
||||||
## Rhino ##
|
|
||||||
|
|
||||||
Rhino is distributed under the following licenses:
|
|
||||||
|
|
||||||
### MPL/GPL License ###
|
|
||||||
The majority of the source code for Rhino is available under a MPL 1.1/GPL 2.0
|
|
||||||
license. JSDoc 3 uses the source code under the MPL 1.1 license, which is
|
|
||||||
included in this distribution.
|
|
||||||
|
|
||||||
### License for portions of the Rhino debugger ###
|
|
||||||
Additionally, some files are available under the BSD 3-clause license:
|
|
||||||
|
|
||||||
> Copyright 1997, 1998 Sun Microsystems, Inc. All Rights Reserved.
|
|
||||||
>
|
|
||||||
> Redistribution and use in source and binary forms, with or without
|
|
||||||
> modification, are permitted provided that the following conditions are met:
|
|
||||||
>
|
|
||||||
> - Redistributions of source code must retain the above copyright notice,
|
|
||||||
> this list of conditions and the following disclaimer.
|
|
||||||
> - Redistributions in binary form must reproduce the above copyright
|
|
||||||
> notice, this list of conditions and the following disclaimer in the
|
|
||||||
> documentation and/or other materials provided with the distribution.
|
|
||||||
> - Neither the name of Sun Microsystems nor the names of its contributors
|
|
||||||
> may be used to endorse or promote products derived from this software
|
|
||||||
> without specific prior written permission.
|
|
||||||
>
|
|
||||||
> THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
> AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
> IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
> DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
|
||||||
> FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
> DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
||||||
> SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
||||||
> CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
||||||
> OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
> OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
### Source Code ###
|
|
||||||
The source code for Rhino is available at:
|
|
||||||
https://github.com/hegemonic/rhino
|
|
||||||
|
|
||||||
|
|
||||||
## Underscore.js ##
|
|
||||||
|
|
||||||
Underscore.js is distributed under the MIT license, which is reproduced above.
|
|
||||||
|
|
||||||
Copyright (c) 2009-2012 Jeremy Ashkenas, DocumentCloud.
|
|
||||||
|
|
||||||
The source code for Underscore.js is available at:
|
|
||||||
https://github.com/documentcloud/underscore
|
|
||||||
|
|
||||||
|
|
||||||
## wrench-js ##
|
|
||||||
|
|
||||||
wrench-js is distributed under the MIT license, which is reproduced above.
|
|
||||||
|
|
||||||
Copyright (c) 2010 Ryan McGrath.
|
|
||||||
|
|
||||||
The source code for wrench-js is available at:
|
|
||||||
https://github.com/ryanmcgrath/wrench-js
|
|
|
@ -1,116 +0,0 @@
|
||||||
JSDoc 3
|
|
||||||
=======
|
|
||||||
[![Build Status](https://secure.travis-ci.org/jsdoc3/jsdoc.png?branch=master)](http://travis-ci.org/jsdoc3/jsdoc)
|
|
||||||
|
|
||||||
An inline API documentation processor for JavaScript. JSDoc 3 is intended to be
|
|
||||||
an upgrade to JsDoc Toolkit (JSDoc 2).
|
|
||||||
|
|
||||||
Want to contribute to JSDoc? Please read `CONTRIBUTING.md`.
|
|
||||||
|
|
||||||
|
|
||||||
Installation
|
|
||||||
------------
|
|
||||||
|
|
||||||
Use git to clone the [official JSDoc repository](https://github.com/jsdoc3/jsdoc):
|
|
||||||
|
|
||||||
git clone git@github.com:jsdoc3/jsdoc.git
|
|
||||||
|
|
||||||
Alternatively, you can download a .zip file for the
|
|
||||||
[latest development version](https://github.com/jsdoc3/jsdoc/archive/master.zip)
|
|
||||||
or a [previous release](https://github.com/jsdoc3/jsdoc/tags).
|
|
||||||
|
|
||||||
You can also install JSDoc within a Node.js project's `node_modules` directory
|
|
||||||
using npm. To install the latest development version, change directories to your
|
|
||||||
Node.js project, then run the following command:
|
|
||||||
|
|
||||||
npm install git://github.com/jsdoc3/jsdoc.git
|
|
||||||
|
|
||||||
Or to install JSDoc globally:
|
|
||||||
|
|
||||||
npm install -g git://github.com/jsdoc3/jsdoc.git
|
|
||||||
|
|
||||||
**Note**: Although you can install JSDoc with npm, JSDoc does not currently run
|
|
||||||
on Node.js.
|
|
||||||
|
|
||||||
|
|
||||||
Usage
|
|
||||||
-----
|
|
||||||
|
|
||||||
This example assumes that your working directory is the JSDoc application base
|
|
||||||
directory:
|
|
||||||
|
|
||||||
./jsdoc yourSourceCodeFile.js
|
|
||||||
|
|
||||||
For information about the supported command-line options, use the `--help`
|
|
||||||
option.
|
|
||||||
|
|
||||||
./jsdoc --help
|
|
||||||
|
|
||||||
Generated documentation will appear in the folder specified by the
|
|
||||||
`--destination` option, or in a folder named "out" by default.
|
|
||||||
|
|
||||||
|
|
||||||
Dependencies
|
|
||||||
------------
|
|
||||||
|
|
||||||
JSDoc 3 uses the Mozilla Rhino engine, which requires Java. JSDoc 3 is known to
|
|
||||||
work with version 1.6.0_24 of Java.
|
|
||||||
|
|
||||||
JSDoc 3 uses advanced features in Mozilla Rhino that are only available in or
|
|
||||||
after version 1.7R3. In addition, JSDoc 3 requires several customizations to the
|
|
||||||
standard Rhino distribution. The customized version of Rhino is included with
|
|
||||||
JSDoc.
|
|
||||||
|
|
||||||
In rare cases, users may have their Java CLASSPATH configured to override the
|
|
||||||
included Rhino and point to an older version of Rhino instead. If this is the
|
|
||||||
case, simply correct the CLASSPATH to remove the older Rhino. (On OS X, you may
|
|
||||||
need to remove the file `~/Library/Java/Extensions/js.jar`.)
|
|
||||||
|
|
||||||
The version of Rhino distributed with JSDoc 3 can be found here:
|
|
||||||
https://github.com/hegemonic/rhino
|
|
||||||
|
|
||||||
|
|
||||||
Debugging
|
|
||||||
---------
|
|
||||||
|
|
||||||
Rhino is not always very friendly when it comes to reporting errors in
|
|
||||||
JavaScript. Luckily, it comes with a full-on debugger included that can be much
|
|
||||||
more useful than a simple stack trace. To invoke JSDoc with the debugger, run
|
|
||||||
the following command on Windows:
|
|
||||||
|
|
||||||
jsdoc --debug
|
|
||||||
|
|
||||||
Or on OS X, Linux, and other POSIX-compliant systems:
|
|
||||||
|
|
||||||
./jsdoc --debug
|
|
||||||
|
|
||||||
If you can't get the short-form commands to work, try invoking Java directly:
|
|
||||||
|
|
||||||
java -cp lib/js.jar org.mozilla.javascript.tools.debugger.Main \
|
|
||||||
-debug -modules node_modules -modules rhino -modules lib -modules . \
|
|
||||||
jsdoc.js your/script.js
|
|
||||||
|
|
||||||
Note: `--debug` must be the first argument to the short-form command.
|
|
||||||
|
|
||||||
This will open a debugging window. Click Debug > Break on Exceptions, then click
|
|
||||||
Run. If there is an error, you should see exactly where it is in the source
|
|
||||||
code.
|
|
||||||
|
|
||||||
|
|
||||||
See Also
|
|
||||||
--------
|
|
||||||
|
|
||||||
Project Documentation: <http://usejsdoc.org/> (under development)
|
|
||||||
Project Documentation Source: <https://github.com/jsdoc3/jsdoc3.github.com>
|
|
||||||
JSDoc User's Group: <http://groups.google.com/group/jsdoc-users>
|
|
||||||
JSDoc 3 Ant Task: <https://github.com/jannon/jsdoc3-ant-task>
|
|
||||||
Project Announcements: <http://twitter.com/jsdoc3>
|
|
||||||
|
|
||||||
|
|
||||||
License
|
|
||||||
-------
|
|
||||||
|
|
||||||
JSDoc 3 is copyright (c) 2011-2012 Michael Mathews <micmath@gmail.com>.
|
|
||||||
|
|
||||||
JSDoc 3 is free software, licensed under the Apache License, Version 2.0. See
|
|
||||||
the file `LICENSE.md` in this distribution for more details.
|
|
|
@ -1,202 +0,0 @@
|
||||||
|
|
||||||
Apache License
|
|
||||||
Version 2.0, January 2004
|
|
||||||
http://www.apache.org/licenses/
|
|
||||||
|
|
||||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
||||||
|
|
||||||
1. Definitions.
|
|
||||||
|
|
||||||
"License" shall mean the terms and conditions for use, reproduction,
|
|
||||||
and distribution as defined by Sections 1 through 9 of this document.
|
|
||||||
|
|
||||||
"Licensor" shall mean the copyright owner or entity authorized by
|
|
||||||
the copyright owner that is granting the License.
|
|
||||||
|
|
||||||
"Legal Entity" shall mean the union of the acting entity and all
|
|
||||||
other entities that control, are controlled by, or are under common
|
|
||||||
control with that entity. For the purposes of this definition,
|
|
||||||
"control" means (i) the power, direct or indirect, to cause the
|
|
||||||
direction or management of such entity, whether by contract or
|
|
||||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
||||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
||||||
|
|
||||||
"You" (or "Your") shall mean an individual or Legal Entity
|
|
||||||
exercising permissions granted by this License.
|
|
||||||
|
|
||||||
"Source" form shall mean the preferred form for making modifications,
|
|
||||||
including but not limited to software source code, documentation
|
|
||||||
source, and configuration files.
|
|
||||||
|
|
||||||
"Object" form shall mean any form resulting from mechanical
|
|
||||||
transformation or translation of a Source form, including but
|
|
||||||
not limited to compiled object code, generated documentation,
|
|
||||||
and conversions to other media types.
|
|
||||||
|
|
||||||
"Work" shall mean the work of authorship, whether in Source or
|
|
||||||
Object form, made available under the License, as indicated by a
|
|
||||||
copyright notice that is included in or attached to the work
|
|
||||||
(an example is provided in the Appendix below).
|
|
||||||
|
|
||||||
"Derivative Works" shall mean any work, whether in Source or Object
|
|
||||||
form, that is based on (or derived from) the Work and for which the
|
|
||||||
editorial revisions, annotations, elaborations, or other modifications
|
|
||||||
represent, as a whole, an original work of authorship. For the purposes
|
|
||||||
of this License, Derivative Works shall not include works that remain
|
|
||||||
separable from, or merely link (or bind by name) to the interfaces of,
|
|
||||||
the Work and Derivative Works thereof.
|
|
||||||
|
|
||||||
"Contribution" shall mean any work of authorship, including
|
|
||||||
the original version of the Work and any modifications or additions
|
|
||||||
to that Work or Derivative Works thereof, that is intentionally
|
|
||||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
||||||
or by an individual or Legal Entity authorized to submit on behalf of
|
|
||||||
the copyright owner. For the purposes of this definition, "submitted"
|
|
||||||
means any form of electronic, verbal, or written communication sent
|
|
||||||
to the Licensor or its representatives, including but not limited to
|
|
||||||
communication on electronic mailing lists, source code control systems,
|
|
||||||
and issue tracking systems that are managed by, or on behalf of, the
|
|
||||||
Licensor for the purpose of discussing and improving the Work, but
|
|
||||||
excluding communication that is conspicuously marked or otherwise
|
|
||||||
designated in writing by the copyright owner as "Not a Contribution."
|
|
||||||
|
|
||||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
||||||
on behalf of whom a Contribution has been received by Licensor and
|
|
||||||
subsequently incorporated within the Work.
|
|
||||||
|
|
||||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
copyright license to reproduce, prepare Derivative Works of,
|
|
||||||
publicly display, publicly perform, sublicense, and distribute the
|
|
||||||
Work and such Derivative Works in Source or Object form.
|
|
||||||
|
|
||||||
3. Grant of Patent License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
(except as stated in this section) patent license to make, have made,
|
|
||||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
||||||
where such license applies only to those patent claims licensable
|
|
||||||
by such Contributor that are necessarily infringed by their
|
|
||||||
Contribution(s) alone or by combination of their Contribution(s)
|
|
||||||
with the Work to which such Contribution(s) was submitted. If You
|
|
||||||
institute patent litigation against any entity (including a
|
|
||||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
||||||
or a Contribution incorporated within the Work constitutes direct
|
|
||||||
or contributory patent infringement, then any patent licenses
|
|
||||||
granted to You under this License for that Work shall terminate
|
|
||||||
as of the date such litigation is filed.
|
|
||||||
|
|
||||||
4. Redistribution. You may reproduce and distribute copies of the
|
|
||||||
Work or Derivative Works thereof in any medium, with or without
|
|
||||||
modifications, and in Source or Object form, provided that You
|
|
||||||
meet the following conditions:
|
|
||||||
|
|
||||||
(a) You must give any other recipients of the Work or
|
|
||||||
Derivative Works a copy of this License; and
|
|
||||||
|
|
||||||
(b) You must cause any modified files to carry prominent notices
|
|
||||||
stating that You changed the files; and
|
|
||||||
|
|
||||||
(c) You must retain, in the Source form of any Derivative Works
|
|
||||||
that You distribute, all copyright, patent, trademark, and
|
|
||||||
attribution notices from the Source form of the Work,
|
|
||||||
excluding those notices that do not pertain to any part of
|
|
||||||
the Derivative Works; and
|
|
||||||
|
|
||||||
(d) If the Work includes a "NOTICE" text file as part of its
|
|
||||||
distribution, then any Derivative Works that You distribute must
|
|
||||||
include a readable copy of the attribution notices contained
|
|
||||||
within such NOTICE file, excluding those notices that do not
|
|
||||||
pertain to any part of the Derivative Works, in at least one
|
|
||||||
of the following places: within a NOTICE text file distributed
|
|
||||||
as part of the Derivative Works; within the Source form or
|
|
||||||
documentation, if provided along with the Derivative Works; or,
|
|
||||||
within a display generated by the Derivative Works, if and
|
|
||||||
wherever such third-party notices normally appear. The contents
|
|
||||||
of the NOTICE file are for informational purposes only and
|
|
||||||
do not modify the License. You may add Your own attribution
|
|
||||||
notices within Derivative Works that You distribute, alongside
|
|
||||||
or as an addendum to the NOTICE text from the Work, provided
|
|
||||||
that such additional attribution notices cannot be construed
|
|
||||||
as modifying the License.
|
|
||||||
|
|
||||||
You may add Your own copyright statement to Your modifications and
|
|
||||||
may provide additional or different license terms and conditions
|
|
||||||
for use, reproduction, or distribution of Your modifications, or
|
|
||||||
for any such Derivative Works as a whole, provided Your use,
|
|
||||||
reproduction, and distribution of the Work otherwise complies with
|
|
||||||
the conditions stated in this License.
|
|
||||||
|
|
||||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
||||||
any Contribution intentionally submitted for inclusion in the Work
|
|
||||||
by You to the Licensor shall be under the terms and conditions of
|
|
||||||
this License, without any additional terms or conditions.
|
|
||||||
Notwithstanding the above, nothing herein shall supersede or modify
|
|
||||||
the terms of any separate license agreement you may have executed
|
|
||||||
with Licensor regarding such Contributions.
|
|
||||||
|
|
||||||
6. Trademarks. This License does not grant permission to use the trade
|
|
||||||
names, trademarks, service marks, or product names of the Licensor,
|
|
||||||
except as required for reasonable and customary use in describing the
|
|
||||||
origin of the Work and reproducing the content of the NOTICE file.
|
|
||||||
|
|
||||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
||||||
agreed to in writing, Licensor provides the Work (and each
|
|
||||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
||||||
implied, including, without limitation, any warranties or conditions
|
|
||||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
||||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
||||||
appropriateness of using or redistributing the Work and assume any
|
|
||||||
risks associated with Your exercise of permissions under this License.
|
|
||||||
|
|
||||||
8. Limitation of Liability. In no event and under no legal theory,
|
|
||||||
whether in tort (including negligence), contract, or otherwise,
|
|
||||||
unless required by applicable law (such as deliberate and grossly
|
|
||||||
negligent acts) or agreed to in writing, shall any Contributor be
|
|
||||||
liable to You for damages, including any direct, indirect, special,
|
|
||||||
incidental, or consequential damages of any character arising as a
|
|
||||||
result of this License or out of the use or inability to use the
|
|
||||||
Work (including but not limited to damages for loss of goodwill,
|
|
||||||
work stoppage, computer failure or malfunction, or any and all
|
|
||||||
other commercial damages or losses), even if such Contributor
|
|
||||||
has been advised of the possibility of such damages.
|
|
||||||
|
|
||||||
9. Accepting Warranty or Additional Liability. While redistributing
|
|
||||||
the Work or Derivative Works thereof, You may choose to offer,
|
|
||||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
||||||
or other liability obligations and/or rights consistent with this
|
|
||||||
License. However, in accepting such obligations, You may act only
|
|
||||||
on Your own behalf and on Your sole responsibility, not on behalf
|
|
||||||
of any other Contributor, and only if You agree to indemnify,
|
|
||||||
defend, and hold each Contributor harmless for any liability
|
|
||||||
incurred by, or claims asserted against, such Contributor by reason
|
|
||||||
of your accepting any such warranty or additional liability.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
APPENDIX: How to apply the Apache License to your work.
|
|
||||||
|
|
||||||
To apply the Apache License to your work, attach the following
|
|
||||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
||||||
replaced with your own identifying information. (Don't include
|
|
||||||
the brackets!) The text should be enclosed in the appropriate
|
|
||||||
comment syntax for the file format. We also recommend that a
|
|
||||||
file or class name and description of purpose be included on the
|
|
||||||
same "printed page" as the copyright notice for easier
|
|
||||||
identification within third-party archives.
|
|
||||||
|
|
||||||
Copyright [yyyy] [name of copyright owner]
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
|
@ -1,17 +0,0 @@
|
||||||
{
|
|
||||||
"tags": {
|
|
||||||
"allowUnknownTags": true
|
|
||||||
},
|
|
||||||
"source": {
|
|
||||||
"includePattern": ".+\\.js(doc)?$",
|
|
||||||
"excludePattern": "(^|\\/|\\\\)_"
|
|
||||||
},
|
|
||||||
"plugins": [],
|
|
||||||
"templates": {
|
|
||||||
"cleverLinks": false,
|
|
||||||
"monospaceLinks": false,
|
|
||||||
"default": {
|
|
||||||
"outputSourceFiles": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,122 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<title>JSDoc: Namespace: app</title>
|
|
||||||
|
|
||||||
<script src="scripts/prettify/prettify.js"> </script>
|
|
||||||
<script src="scripts/prettify/lang-css.js"> </script>
|
|
||||||
<!--[if lt IE 9]>
|
|
||||||
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
|
||||||
<![endif]-->
|
|
||||||
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
|
|
||||||
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
|
|
||||||
<div id="main">
|
|
||||||
|
|
||||||
<h1 class="page-title">Namespace: app</h1>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<section>
|
|
||||||
|
|
||||||
<header>
|
|
||||||
<h2>
|
|
||||||
app
|
|
||||||
</h2>
|
|
||||||
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<article>
|
|
||||||
<div class="container-overview">
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div class="description">Data that must be shared across the entire application.</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<dl class="details">
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
|
||||||
<a href="jsdoc.js.html">jsdoc.js</a>, <a href="jsdoc.js.html#line82">line 82</a>
|
|
||||||
</li></ul></dd>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</dl>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</article>
|
|
||||||
|
|
||||||
</section>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<nav>
|
|
||||||
<h2><a href="index.html">Index</a></h2><h3>Namespaces</h3><ul><li><a href="app.html">app</a></li><li><a href="env.html">env</a></li></ul><h3>Global</h3><ul><li><a href="global.html#main">main</a></li></ul>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<br clear="both">
|
|
||||||
|
|
||||||
<footer>
|
|
||||||
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.2.0-dev</a> on Mon May 20 2013 17:20:54 GMT+0300 (EEST)
|
|
||||||
</footer>
|
|
||||||
|
|
||||||
<script> prettyPrint(); </script>
|
|
||||||
<script src="scripts/linenumber.js"> </script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,720 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<title>JSDoc: Class: bookAppointment</title>
|
|
||||||
|
|
||||||
<script src="scripts/prettify/prettify.js"> </script>
|
|
||||||
<script src="scripts/prettify/lang-css.js"> </script>
|
|
||||||
<!--[if lt IE 9]>
|
|
||||||
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
|
||||||
<![endif]-->
|
|
||||||
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
|
|
||||||
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
|
|
||||||
<div id="main">
|
|
||||||
|
|
||||||
<h1 class="page-title">Class: bookAppointment</h1>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<section>
|
|
||||||
|
|
||||||
<header>
|
|
||||||
<h2>
|
|
||||||
bookAppointment
|
|
||||||
</h2>
|
|
||||||
|
|
||||||
<div class="class-description">Implelements the js part of the appointment booking page.</div>
|
|
||||||
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<article>
|
|
||||||
<div class="container-overview">
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<dt>
|
|
||||||
<h4 class="name" id="bookAppointment"><span class="type-signature"></span>new bookAppointment<span class="signature">()</span><span class="type-signature"></span></h4>
|
|
||||||
|
|
||||||
|
|
||||||
</dt>
|
|
||||||
<dd>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="description">
|
|
||||||
This class implements the book appointment page functionality.
|
|
||||||
Once the initialize() method is called the page is fully functional
|
|
||||||
and can serve the appointment booking process.
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<dl class="details">
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
|
||||||
<a href="book_appointment.js.html">book_appointment.js</a>, <a href="book_appointment.js.html#line8">line 8</a>
|
|
||||||
</li></ul></dd>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</dl>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</dd>
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<h3 class="subsection-title">Methods</h3>
|
|
||||||
|
|
||||||
<dl>
|
|
||||||
|
|
||||||
<dt>
|
|
||||||
<h4 class="name" id="bindEventHandlers"><span class="type-signature"><static> </span>bindEventHandlers<span class="signature">()</span><span class="type-signature"></span></h4>
|
|
||||||
|
|
||||||
|
|
||||||
</dt>
|
|
||||||
<dd>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="description">
|
|
||||||
This method binds the necessary event handlers
|
|
||||||
for the book appointments page.
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<dl class="details">
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
|
||||||
<a href="book_appointment.js.html">book_appointment.js</a>, <a href="book_appointment.js.html#line55">line 55</a>
|
|
||||||
</li></ul></dd>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</dl>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</dd>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<dt>
|
|
||||||
<h4 class="name" id="calcEndDatetime"><span class="type-signature"><static> </span>calcEndDatetime<span class="signature">()</span><span class="type-signature"> → {string}</span></h4>
|
|
||||||
|
|
||||||
|
|
||||||
</dt>
|
|
||||||
<dd>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="description">
|
|
||||||
This method calculates the end datetime of the current appointment.
|
|
||||||
End datetime is depending on the service and start datetime fieldss.
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<dl class="details">
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
|
||||||
<a href="book_appointment.js.html">book_appointment.js</a>, <a href="book_appointment.js.html#line288">line 288</a>
|
|
||||||
</li></ul></dd>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</dl>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<h5>Returns:</h5>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="param-desc">
|
|
||||||
Returns the end datetime in string format.
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<dl>
|
|
||||||
<dt>
|
|
||||||
Type
|
|
||||||
</dt>
|
|
||||||
<dd>
|
|
||||||
|
|
||||||
<span class="param-type">string</span>
|
|
||||||
|
|
||||||
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</dd>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<dt>
|
|
||||||
<h4 class="name" id="getAvailableHours"><span class="type-signature"><static> </span>getAvailableHours<span class="signature">(selDate)</span><span class="type-signature"></span></h4>
|
|
||||||
|
|
||||||
|
|
||||||
</dt>
|
|
||||||
<dd>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="description">
|
|
||||||
This function makes an ajax call and returns the available
|
|
||||||
hours for the selected service, provider and date.
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<h5>Parameters:</h5>
|
|
||||||
|
|
||||||
|
|
||||||
<table class="params">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
|
|
||||||
<th>Name</th>
|
|
||||||
|
|
||||||
|
|
||||||
<th>Type</th>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<th class="last">Description</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
|
|
||||||
<tbody>
|
|
||||||
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
|
|
||||||
<td class="name"><code>selDate</code></td>
|
|
||||||
|
|
||||||
|
|
||||||
<td class="type">
|
|
||||||
|
|
||||||
|
|
||||||
<span class="param-type">string</span>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</td>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<td class="description last">The selected date of which the available
|
|
||||||
hours we need to receive.</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<dl class="details">
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
|
||||||
<a href="book_appointment.js.html">book_appointment.js</a>, <a href="book_appointment.js.html#line155">line 155</a>
|
|
||||||
</li></ul></dd>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</dl>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</dd>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<dt>
|
|
||||||
<h4 class="name" id="initialize"><span class="type-signature"><static> </span>initialize<span class="signature">(bindEventHandlers)</span><span class="type-signature"></span></h4>
|
|
||||||
|
|
||||||
|
|
||||||
</dt>
|
|
||||||
<dd>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="description">
|
|
||||||
This method initializes the book appointment page.
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<h5>Parameters:</h5>
|
|
||||||
|
|
||||||
|
|
||||||
<table class="params">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
|
|
||||||
<th>Name</th>
|
|
||||||
|
|
||||||
|
|
||||||
<th>Type</th>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<th class="last">Description</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
|
|
||||||
<tbody>
|
|
||||||
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
|
|
||||||
<td class="name"><code>bindEventHandlers</code></td>
|
|
||||||
|
|
||||||
|
|
||||||
<td class="type">
|
|
||||||
|
|
||||||
|
|
||||||
<span class="param-type">bool</span>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</td>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<td class="description last">(OPTIONAL) Determines wether
|
|
||||||
the default event handlers will be binded to the dom elements.</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<dl class="details">
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
|
||||||
<a href="book_appointment.js.html">book_appointment.js</a>, <a href="book_appointment.js.html#line15">line 15</a>
|
|
||||||
</li></ul></dd>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</dl>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</dd>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<dt>
|
|
||||||
<h4 class="name" id="updateConfirmData"><span class="type-signature"><static> </span>updateConfirmData<span class="signature">()</span><span class="type-signature"></span></h4>
|
|
||||||
|
|
||||||
|
|
||||||
</dt>
|
|
||||||
<dd>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="description">
|
|
||||||
Every time this function is executed, it updates the confirmation
|
|
||||||
page with the latest customer settigns and input for the appointment
|
|
||||||
booking.
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<dl class="details">
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
|
||||||
<a href="book_appointment.js.html">book_appointment.js</a>, <a href="book_appointment.js.html#line233">line 233</a>
|
|
||||||
</li></ul></dd>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</dl>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</dd>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<dt>
|
|
||||||
<h4 class="name" id="validateCustomerDataForm"><span class="type-signature"><static> </span>validateCustomerDataForm<span class="signature">()</span><span class="type-signature"> → {bool}</span></h4>
|
|
||||||
|
|
||||||
|
|
||||||
</dt>
|
|
||||||
<dd>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="description">
|
|
||||||
This function validates the customer's data input.
|
|
||||||
It only checks for empty fields by the time.
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<dl class="details">
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
|
||||||
<a href="book_appointment.js.html">book_appointment.js</a>, <a href="book_appointment.js.html#line214">line 214</a>
|
|
||||||
</li></ul></dd>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</dl>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<h5>Returns:</h5>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="param-desc">
|
|
||||||
Returns the validation result.
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<dl>
|
|
||||||
<dt>
|
|
||||||
Type
|
|
||||||
</dt>
|
|
||||||
<dd>
|
|
||||||
|
|
||||||
<span class="param-type">bool</span>
|
|
||||||
|
|
||||||
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</dd>
|
|
||||||
|
|
||||||
</dl>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</article>
|
|
||||||
|
|
||||||
</section>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<nav>
|
|
||||||
<h2><a href="index.html">Index</a></h2><h3>Classes</h3><ul><li><a href="bookAppointment.html">bookAppointment</a></li></ul>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<br clear="both">
|
|
||||||
|
|
||||||
<footer>
|
|
||||||
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.2.0-dev</a> on Mon May 20 2013 17:24:34 GMT+0300 (EEST)
|
|
||||||
</footer>
|
|
||||||
|
|
||||||
<script> prettyPrint(); </script>
|
|
||||||
<script src="scripts/linenumber.js"> </script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|