diff --git a/Controllers/IndexController.php b/Controllers/IndexController.php new file mode 100644 index 0000000..3670871 --- /dev/null +++ b/Controllers/IndexController.php @@ -0,0 +1,15 @@ + + */ +namespace Application\Controllers; +use Blossom\Classes\Controller; + +class IndexController extends Controller +{ + public function index() + { + } +} diff --git a/Controllers/LoginController.php b/Controllers/LoginController.php new file mode 100644 index 0000000..03ef8f7 --- /dev/null +++ b/Controllers/LoginController.php @@ -0,0 +1,88 @@ + + */ +namespace Application\Controllers; +use Blossom\Classes\Controller; +use Blossom\Classes\Template; +use Blossom\Classes\Block; +use Application\Models\Person; + +class LoginController extends Controller +{ + private $return_url; + + public function __construct(Template $template) + { + parent::__construct($template); + $this->return_url = !empty($_REQUEST['return_url']) ? $_REQUEST['return_url'] : BASE_URL; + } + + /** + * Attempts to authenticate users via CAS + */ + public function index() + { + // If they don't have CAS configured, send them onto the application's + // internal authentication system + if (!defined('CAS')) { + header('Location: '.BASE_URL.'/login/login?return_url='.$this->return_url); + exit(); + } + + require_once CAS.'/CAS.php'; + \phpCAS::client(CAS_VERSION_2_0, CAS_SERVER, 443, CAS_URI, false); + \phpCAS::setNoCasServerValidation(); + \phpCAS::forceAuthentication(); + // at this step, the user has been authenticated by the CAS server + // and the user's login name can be read with phpCAS::getUser(). + + // They may be authenticated according to CAS, + // but that doesn't mean they have person record + // and even if they have a person record, they may not + // have a user account for that person record. + try { + $_SESSION['USER'] = new Person(\phpCAS::getUser()); + header("Location: {$this->return_url}"); + exit(); + } + catch (\Exception $e) { + $_SESSION['errorMessages'][] = $e; + } + + $this->template->blocks[] = new Block('loginForm.inc',array('return_url'=>$this->return_url)); + } + + /** + * Attempts to authenticate users based on AuthenticationMethod + */ + public function login() + { + if (isset($_POST['username'])) { + try { + $person = new Person($_POST['username']); + if ($person->authenticate($_POST['password'])) { + $_SESSION['USER'] = $person; + header('Location: '.$this->return_url); + exit(); + } + else { + throw new \Exception('invalidLogin'); + } + } + catch (\Exception $e) { + $_SESSION['errorMessages'][] = $e; + } + } + $this->template->blocks[] = new Block('loginForm.inc',array('return_url'=>$this->return_url)); + } + + public function logout() + { + session_destroy(); + header('Location: '.$this->return_url); + exit(); + } +} diff --git a/Controllers/PeopleController.php b/Controllers/PeopleController.php new file mode 100644 index 0000000..5e17bb3 --- /dev/null +++ b/Controllers/PeopleController.php @@ -0,0 +1,70 @@ + + */ +namespace Application\Controllers; +use Application\Models\Person; +use Application\Models\PeopleTable; +use Blossom\Classes\Controller; +use Blossom\Classes\Block; + +class PeopleController extends Controller +{ + public function index() + { + $table = new PeopleTable(); + $people = $table->find(null, null, true); + + $page = !empty($_GET['page']) ? (int)$_GET['page'] : 1; + $people->setCurrentPageNumber($page); + $people->setItemCountPerPage(20); + + $this->template->blocks[] = new Block('people/list.inc', ['people' =>$people]); + $this->template->blocks[] = new Block('pageNavigation.inc', ['paginator'=>$people]); + } + + public function view() + { + try { + $person = new Person($_REQUEST['person_id']); + $this->template->blocks[] = new Block('people/info.inc',array('person'=>$person)); + } + catch (\Exception $e) { + $_SESSION['errorMessages'][] = $e; + } + + } + + public function update() + { + if (isset($_REQUEST['person_id']) && $_REQUEST['person_id']) { + try { + $person = new Person($_REQUEST['person_id']); + } + catch (\Exception $e) { + $_SESSION['errorMessages'][] = $e; + header('Location: '.BASE_URL.'/people'); + exit(); + } + } + else { + $person = new Person(); + } + + if (isset($_POST['firstname'])) { + $person->handleUpdate($_POST); + try { + $person->save(); + header('Location: '.BASE_URL.'/people'); + exit(); + } + catch (\Exception $e) { + $_SESSION['errorMessages'][] = $e; + } + } + + $this->template->blocks[] = new Block('people/updateForm.inc',array('person'=>$person)); + } +} diff --git a/Controllers/UsersController.php b/Controllers/UsersController.php new file mode 100644 index 0000000..669c0d2 --- /dev/null +++ b/Controllers/UsersController.php @@ -0,0 +1,66 @@ + + */ +namespace Application\Controllers; +use Application\Models\Person; +use Application\Models\PeopleTable; +use Blossom\Classes\Controller; +use Blossom\Classes\Block; +use Blossom\Classes\Database; +use Zend\Paginator\Paginator; +use Zend\Paginator\Adapter\DbSelect; + +class UsersController extends Controller +{ + public function index() + { + $people = new PeopleTable(); + $users = $people->find(['user_account'=>true], null, true); + + $page = !empty($_GET['page']) ? (int)$_GET['page'] : 1; + $users->setCurrentPageNumber($page); + $users->setItemCountPerPage(20); + + $this->template->blocks[] = new Block('users/list.inc',array('users'=>$users)); + $this->template->blocks[] = new Block('pageNavigation.inc', ['paginator'=>$users]); + } + + public function update() + { + $person = isset($_REQUEST['user_id']) ? new Person($_REQUEST['user_id']) : new Person(); + + if (isset($_POST['username'])) { + try { + $person->handleUpdateUserAccount($_POST); + $person->save(); + header('Location: '.BASE_URL.'/users'); + exit(); + } + catch (\Exception $e) { + $_SESSION['errorMessages'][] = $e; + } + } + + if ($person->getId()) { + $this->template->blocks[] = new Block('people/info.inc',array('person'=>$person)); + } + $this->template->blocks[] = new Block('users/updateForm.inc',array('user'=>$person)); + } + + public function delete() + { + try { + $person = new Person($_REQUEST['user_id']); + $person->deleteUserAccount(); + $person->save(); + } + catch (\Exception $e) { + $_SESSION['errorMessages'][] = $e; + } + header('Location: '.BASE_URL.'/users'); + exit(); + } +} diff --git a/Models/PeopleTable.php b/Models/PeopleTable.php new file mode 100644 index 0000000..9ad66e7 --- /dev/null +++ b/Models/PeopleTable.php @@ -0,0 +1,44 @@ + + */ +namespace Application\Models; + +use Blossom\Classes\TableGateway; +use Zend\Db\Sql\Select; + +class PeopleTable extends TableGateway +{ + public function __construct() { parent::__construct('people', __namespace__.'\Person'); } + + /** + * @param array $fields + * @param string|array $order Multi-column sort should be given as an array + * @param bool $paginated Whether to return a paginator or a raw resultSet + * @param int $limit + */ + public function find($fields=null, $order='lastname', $paginated=false, $limit=null) + { + $select = new Select('people'); + if (count($fields)) { + foreach ($fields as $key=>$value) { + switch ($key) { + case 'user_account': + if ($value) { + $select->where('username is not null'); + } + else { + $select->where('username is null'); + } + break; + + default: + $select->where([$key=>$value]); + } + } + } + return parent::performSelect($select, $order, $paginated, $limit); + } +} diff --git a/Models/Person.php b/Models/Person.php new file mode 100644 index 0000000..a2f3c97 --- /dev/null +++ b/Models/Person.php @@ -0,0 +1,258 @@ + + */ +namespace Application\Models; +use Blossom\Classes\ActiveRecord; +use Blossom\Classes\Database; +use Blossom\Classes\ExternalIdentity; + +class Person extends ActiveRecord +{ + protected $tablename = 'people'; + + /** + * Populates the object with data + * + * Passing in an associative array of data will populate this object without + * hitting the database. + * + * Passing in a scalar will load the data from the database. + * This will load all fields in the table as properties of this class. + * You may want to replace this with, or add your own extra, custom loading + * + * @param int|string|array $id (ID, email, username) + */ + public function __construct($id=null) + { + if ($id) { + if (is_array($id)) { + $this->exchangeArray($id); + } + else { + $zend_db = Database::getConnection(); + if (ActiveRecord::isId($id)) { + $sql = 'select * from people where id=?'; + } + elseif (false !== strpos($id,'@')) { + $sql = 'select * from people where email=?'; + } + else { + $sql = 'select * from people where username=?'; + } + $result = $zend_db->createStatement($sql)->execute([$id]); + if (count($result)) { + $this->exchangeArray($result->current()); + } + else { + throw new \Exception('people/unknownPerson'); + } + } + } + else { + // This is where the code goes to generate a new, empty instance. + // Set any default values for properties that need it here + $this->setAuthenticationMethod('local'); + } + } + + /** + * Throws an exception if anything's wrong + * @throws Exception $e + */ + public function validate() + { + // Check for required fields here. Throw an exception if anything is missing. + if (!$this->getFirstname() || !$this->getEmail()) { + throw new \Exception('missingRequiredFields'); + } + + if ($this->getUsername() && !$this->getAuthenticationMethod()) { + $this->setAuthenticationMethod('local'); + } + } + + public function save() + { + parent::save(); + } + + /** + * Removes all the user account related fields from this Person + */ + public function deleteUserAccount() + { + $userAccountFields = array( + 'username', 'password', 'authenticationMethod', 'role' + ); + foreach ($userAccountFields as $f) { + $this->data[$f] = null; + } + } + + + //---------------------------------------------------------------- + // Generic Getters & Setters + //---------------------------------------------------------------- + public function getId() { return parent::get('id'); } + public function getFirstname() { return parent::get('firstname'); } + public function getLastname() { return parent::get('lastname'); } + public function getEmail() { return parent::get('email'); } + + public function setFirstname ($s) { parent::set('firstname', $s); } + public function setLastname ($s) { parent::set('lastname', $s); } + public function setEmail ($s) { parent::set('email', $s); } + + public function getUsername() { return parent::get('username'); } + public function getPassword() { return parent::get('password'); } # Encrypted + public function getRole() { return parent::get('role'); } + public function getAuthenticationMethod() { return parent::get('authenticationMethod'); } + + public function setUsername ($s) { parent::set('username', $s); } + public function setRole ($s) { parent::set('role', $s); } + public function setAuthenticationMethod($s) { parent::set('authenticationMethod', $s); } + + public function setPassword($s) + { + $s = trim($s); + if ($s) { $this->data['password'] = sha1($s); } + else { $this->data['password'] = null; } + } + + /** + * @param array $post + */ + public function handleUpdate($post) + { + $fields = array( 'firstname', 'middlename', 'lastname', 'email' ); + foreach ($fields as $field) { + if (isset($post[$field])) { + $set = 'set'.ucfirst($field); + $this->$set($post[$field]); + } + } + } + + /** + * @param array $post + */ + public function handleUpdateUserAccount($post) + { + $fields = array( + 'firstname','lastname','email', + 'username','authenticationMethod','role' + ); + foreach ($fields as $f) { + if (isset($post[$f])) { + $set = 'set'.ucfirst($f); + $this->$set($post[$f]); + } + if (!empty($post['password'])) { + $this->setPassword($post['password']); + } + } + + $method = $this->getAuthenticationMethod(); + if ($this->getUsername() && $method && $method != 'local') { + $class = "Blossom\\Classes\\$method"; + $identity = new $class($this->getUsername()); + $this->populateFromExternalIdentity($identity); + } + } + + //---------------------------------------------------------------- + // User Authentication + //---------------------------------------------------------------- + /** + * Should provide the list of methods supported + * + * There should always be at least one method, called "local" + * Additional methods must match classes that implement External Identities + * See: ExternalIdentity.php + * + * @return array + */ + public static function getAuthenticationMethods() + { + global $DIRECTORY_CONFIG; + return array_merge(array('local'), array_keys($DIRECTORY_CONFIG)); + } + + /** + * Determines which authentication scheme to use for the user and calls the appropriate method + * + * Local users will get authenticated against the database + * Other authenticationMethods will need to write a class implementing ExternalIdentity + * See: /libraries/framework/classes/ExternalIdentity.php + * + * @param string $password + * @return boolean + */ + public function authenticate($password) + { + if ($this->getUsername()) { + switch($this->getAuthenticationMethod()) { + case "local": + return $this->getPassword()==sha1($password); + break; + + default: + $method = $this->getAuthenticationMethod(); + $class = "Blossom\\Classes\\$method"; + return $class::authenticate($this->getUsername(),$password); + } + } + } + + /** + * Checks if the user is supposed to have acces to the resource + * + * This is implemented by checking against a Zend_Acl object + * The Zend_Acl should be created in configuration.inc + * + * @param string $resource + * @param string $action + * @return boolean + */ + public static function isAllowed($resource, $action=null) + { + global $ZEND_ACL; + $role = 'Anonymous'; + if (isset($_SESSION['USER']) && $_SESSION['USER']->getRole()) { + $role = $_SESSION['USER']->getRole(); + } + return $ZEND_ACL->isAllowed($role, $resource, $action); + } + + //---------------------------------------------------------------- + // Custom Functions + //---------------------------------------------------------------- + public function getUrl() { return BASE_URL.'/people/view?person_id='.$this->getId(); } + public function getUri() { return BASE_URI.'/people/view?person_id='.$this->getId(); } + + /** + * @return string + */ + public function getFullname() + { + return "{$this->getFirstname()} {$this->getLastname()}"; + } + + /** + * @param ExternalIdentity $identity An object implementing ExternalIdentity + */ + public function populateFromExternalIdentity(ExternalIdentity $identity) + { + if (!$this->getFirstname() && $identity->getFirstname()) { + $this->setFirstname($identity->getFirstname()); + } + if (!$this->getLastname() && $identity->getLastname()) { + $this->setLastname($identity->getLastname()); + } + if (!$this->getEmail() && $identity->getEmail()) { + $this->setEmail($identity->getEmail()); + } + } +} diff --git a/access_control.inc b/access_control.inc index 1fbf435..5390e88 100644 --- a/access_control.inc +++ b/access_control.inc @@ -4,31 +4,44 @@ * @license http://www.gnu.org/licenses/agpl.txt GNU/AGPL, see LICENSE.txt * @author Cliff Ingham */ -$ZEND_ACL = new Zend_Acl(); -/** - * Load the roles from the database - */ -$roles = new RoleList(); -$roles->find(); -foreach ($roles as $role) { - $ZEND_ACL = $ZEND_ACL->addRole(new Zend_Acl_Role($role->getName())); -} +use Zend\Permissions\Acl\Acl; +use Zend\Permissions\Acl\Role\GenericRole as Role; +use Zend\Permissions\Acl\Resource\GenericResource as Resource; + +$ZEND_ACL = new Acl(); +$ZEND_ACL->addRole(new Role('Anonymous')) + ->addRole(new Role('Public'), 'Anonymous') + ->addRole(new Role('Staff'), 'Public') + ->addRole(new Role('Administrator'), 'Staff'); /** * Declare all the resources */ -$ZEND_ACL->add(new Zend_Acl_Resource('Users')); -$ZEND_ACL->add(new Zend_Acl_Resource('Deeds')); -$ZEND_ACL->add(new Zend_Acl_Resource('Interments')); -$ZEND_ACL->add(new Zend_Acl_Resource('Cemeteries')); -$ZEND_ACL->add(new Zend_Acl_Resource('Sections')); +$ZEND_ACL->addResource(new Resource('index')); +$ZEND_ACL->addResource(new Resource('people')); +$ZEND_ACL->addResource(new Resource('users')); +$ZEND_ACL->addResource(new Resource('login')); +$ZEND_ACL->addResource(new Resource('deeds')); +$ZEND_ACL->addResource(new Resource('interments')); +$ZEND_ACL->addResource(new Resource('cemeteries')); +$ZEND_ACL->addResource(new Resource('sections')); /** * Assign permissions to the resources */ +$ZEND_ACL->allow(null,'login'); + +// Permissions for unauthenticated browsing +$ZEND_ACL->allow(null, + array('index'), + array('index')); + +// Allow Staff to do stuff +$ZEND_ACL->allow('Staff',['deeds', 'interments']); +$ZEND_ACL->allow('Staff', + ['people', 'cemeteries', 'sections'], + ['index','view']); + // Administrator is allowed access to everything $ZEND_ACL->allow('Administrator'); - -$ZEND_ACL->allow('Editor','Deeds'); -$ZEND_ACL->allow('Editor','Interments'); \ No newline at end of file diff --git a/blocks/html/people/addPersonForm.inc b/blocks/html/people/addPersonForm.inc deleted file mode 100644 index 5f64be7..0000000 --- a/blocks/html/people/addPersonForm.inc +++ /dev/null @@ -1,35 +0,0 @@ - - */ -?> -

Add Person

-
-
Personal Info - - - - - - - - - - - - - - -
-
-
-
- - - -
-
diff --git a/blocks/html/people/info.inc b/blocks/html/people/info.inc new file mode 100644 index 0000000..8d5e13d --- /dev/null +++ b/blocks/html/people/info.inc @@ -0,0 +1,34 @@ + + * @param Person $this->person + */ +use Application\Models\Person; +use Blossom\Classes\View; + +$username = $this->person->getUsername(); +if (!$username && Person::isAllowed('users')) { + $h = $this->template->getHelper('buttonLink'); + $username = $h->buttonLink( + BASE_URI.'/users/update?user_id='.$this->person->getId(), + $this->translate('create_account'), + 'add' + ); +} + +$name = View::escape($this->person->getFullname()); +echo << +

$name

+ + + + + + + +
Email{$this->person->getEmail()}
Username$username
+ +EOT; diff --git a/blocks/html/people/list.inc b/blocks/html/people/list.inc new file mode 100644 index 0000000..229ba06 --- /dev/null +++ b/blocks/html/people/list.inc @@ -0,0 +1,58 @@ + + * @param Zend\Db\ResultSet $people + */ +use Application\Models\Person; +use Blossom\Classes\View; +?> +
+

translate(['person','people',2]); + + $helper = $this->template->getHelper('buttonLink'); + + if (Person::isAllowed('people')) { + echo $helper->buttonLink( + BASE_URI.'/people/update', + $this->translate('add_person'), + 'add' + ); + } + ?> +

+ + + + + + + + + + people as $person) { + $editButton = ''; + if (Person::isAllowed('people')) { + $editButton = $helper->buttonLink( + BASE_URI.'/people/update?person_id='.$person->getId(), + $this->translate('edit'), + 'edit' + ); + } + + $name = View::escape($person->getFullname()); + echo " + + + + + + "; + } + ?> + +
_('username'); ?>_('name'); ?>_(['email','emails',1]); ?>
$editButton{$person->getUsername()}getURL()}\">$name{$person->getEmail()}
+
diff --git a/blocks/html/people/personInfo.inc b/blocks/html/people/personInfo.inc deleted file mode 100644 index 90295fe..0000000 --- a/blocks/html/people/personInfo.inc +++ /dev/null @@ -1,29 +0,0 @@ - - * @param Person $this->person - */ -$username = $this->person->getUsername(); -if (!$username && userIsAllowed('Users')) { - $url = BASE_URL.'/users/addUser.php?person_id='.$this->person->getId(); - $username = " - "; -} - - -$name = View::escape($this->person->getFullname()); -echo " -

$name

- - - - - - - -
Username$username
Email{$this->person->getEmail()}
-"; diff --git a/blocks/html/people/personList.inc b/blocks/html/people/personList.inc deleted file mode 100644 index 36cba3d..0000000 --- a/blocks/html/people/personList.inc +++ /dev/null @@ -1,46 +0,0 @@ - - * @param PersonList $this->personList - */ -?> -
-

- Add A Person - - "; - } - ?> - People -

- - personList as $person) { - $editButton = ''; - - if (userIsAllowed('Users')) { - $editButton = " - - "; - - } - - $name = View::escape($person->getFullname()); - echo " - - - - - - "; - } - ?> -
$editButton{$person->getUsername()}getURL()}\">$name{$person->getEmail()}
-
diff --git a/blocks/html/people/updateForm.inc b/blocks/html/people/updateForm.inc new file mode 100644 index 0000000..dcfc6ef --- /dev/null +++ b/blocks/html/people/updateForm.inc @@ -0,0 +1,42 @@ + + * @param Person $this->person + */ +use Blossom\Classes\View; + +$fields = array('firstname','lastname','email'); +foreach ($fields as $field) { + $get = 'get'.ucfirst($field); + $$field = View::escape($this->person->$get()); +} +$title = $this->person->getId() ? View::escape('Edit '.$this->person->getFirstname()) : 'Add Someone'; +?> +
+

+
+
_('info_person'); ?> + + + + + + + + + + + + + + +
+ template->getHelper('saveAndCancelButtons'); + echo $h->saveAndCancelButtons(BASE_URI.'/people'); + ?> +
+
+
diff --git a/blocks/html/people/updatePersonForm.inc b/blocks/html/people/updatePersonForm.inc deleted file mode 100644 index 201a8ce..0000000 --- a/blocks/html/people/updatePersonForm.inc +++ /dev/null @@ -1,37 +0,0 @@ - - * @param Person $this->person - */ -?> -

Update Person

-
-
Person Info - - - - - - - - - - - - - - - -
-
-
-
- - - -
-
diff --git a/language/en_US.mo b/language/en_US.mo new file mode 100644 index 0000000..dc3ad4e Binary files /dev/null and b/language/en_US.mo differ diff --git a/language/en_US.po b/language/en_US.po new file mode 100644 index 0000000..d0800a8 --- /dev/null +++ b/language/en_US.po @@ -0,0 +1,126 @@ +# Translation +# Copyright (C) 2013 City of Bloomington +# This file is distributed under the same license as the Blossom package. +# +# Cliff Ingham, 2013. +msgid "" +msgstr "" +"Project-Id-Version: uReport 1.9\n" +"Report-Msgid-Bugs-To: dev@bloomington.in.gov\n" +"POT-Creation-Date: 2013-09-20 16:33-0400\n" +"PO-Revision-Date: 2014-08-11 13:43-0500\n" +"Last-Translator: Cliff Ingham \n" +"Language-Team: City of Bloomington \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Poedit 1.5.4\n" +"Language: en_US\n" +"X-Poedit-SourceCharset: UTF-8\n" + +msgid "home" +msgstr "Home" + +msgid "add" +msgstr "Add" + +msgid "edit" +msgstr "Edit" + +msgid "delete" +msgstr "Delete" + +msgid "submit" +msgstr "Submit" + +msgid "save" +msgstr "Save" + +msgid "cancel" +msgstr "Cancel" + +#. This is the short form for "Administrator". This should be an abbreviation +msgid "admin" +msgstr "Admin" + +msgid "login" +msgstr "Login" + +msgid "logout" +msgstr "Logout" + +msgid "messages.signed_in_as" +msgstr "Signed in as %s" + +msgid "help" +msgstr "Help" + +msgid "name" +msgstr "Name" + +msgid "firstname" +msgstr "First Name" + +msgid "middlename" +msgstr "Middle Name" + +msgid "lastname" +msgstr "Last Name" + +msgid "username" +msgstr "Username" + +msgid "password" +msgstr "Password" + +msgid "authenticationMethod" +msgstr "Authentication" + +msgid "role" +msgstr "Role" + +msgid "email" +msgid_plural "emails" +msgstr[0] "Email" +msgstr[1] "Email Addresses" + +msgid "person" +msgid_plural "people" +msgstr[0] "Person" +msgstr[1] "People" + +msgid "user" +msgid_plural "users" +msgstr[0] "User Account" +msgstr[1] "User Accounts" + +msgid "info_person" +msgstr "Person Info" + +msgid "add_person" +msgstr "Add a Person" + +msgid "create_account" +msgstr "Create Account" + +msgid "edit_account" +msgstr "Edit Account" + +msgid "delete_account" +msgstr "Delete Account" + +msgid "interment" +msgid_plural "interments" +msgstr[0] "Interment" +msgstr[1] "Interments" + +msgid "cemetery" +msgid_plural "cemeteries" +msgstr[0] "Cemetery" +msgstr[1] "Cemeteries" + +msgid "deed" +msgid_plural "deeds" +msgstr[0] "Deed" +msgstr[1] "Deeds" diff --git a/public/css/local/layouts/full-width.css b/public/css/local/layouts/full-width.css new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/public/css/local/layouts/full-width.css @@ -0,0 +1 @@ + diff --git a/public/css/local/layouts/three-column.css b/public/css/local/layouts/three-column.css new file mode 100644 index 0000000..4382b7f --- /dev/null +++ b/public/css/local/layouts/three-column.css @@ -0,0 +1,6 @@ +#panel-container { overflow:auto; } +#panel-one { float:left; width:180px; } +#panel-two { float:right; width:180px; } +#content-panel { margin-left: 190px; margin-right: 190px; } + +#footer { clear:both; } diff --git a/public/css/local/layouts/two-column.css b/public/css/local/layouts/two-column.css new file mode 100644 index 0000000..7c43645 --- /dev/null +++ b/public/css/local/layouts/two-column.css @@ -0,0 +1,6 @@ +#panel-container { width:100%; overflow:auto; padding-left:10px; } +#panel-one { width:490px; float:right; padding-left:10px; } +#content-panel { margin-right:495px; border-right:1px solid #999999; width:470px; } +#panel-two { clear:right; width:100%; } + +#footer { clear:both; } diff --git a/public/css/local/reset.css b/public/css/local/reset.css new file mode 100644 index 0000000..f25e4c4 --- /dev/null +++ b/public/css/local/reset.css @@ -0,0 +1,50 @@ +/* + CSS Reset technique copied from Eric Meyer + http://meyerweb.com/eric/thoughts/2007/05/01/reset-reloaded/ +*/ +html, body, div, span, applet, object, iframe, +h1, h2, h3, h4, h5, h6, p, blockquote, pre, +a, abbr, acronym, address, big, cite, code, +del, dfn, em, font, img, ins, kbd, q, s, samp, +small, strike, strong, sub, sup, tt, var, +fieldset, form, label, legend, +table, caption, tbody, tfoot, thead, tr, th, td { + margin: 0; + padding: 0; + border: 0; + outline: 0; + font-weight: inherit; + font-style: inherit; + font-size: 100%; + font-family: inherit; + vertical-align: baseline; +} +/* Links should not be styled to start out with */ +a { text-decoration:none; } +/* remember to define focus styles! */ +:focus { + outline: 0; +} +body { + line-height: 1; + color: black; + background: white; +} +ol, ul { +} +/* tables still need 'cellspacing="0"' in the markup */ +table { + border-collapse: separate; + border-spacing: 0; +} +caption, th, td { + text-align: left; + font-weight: normal; +} +blockquote:before, blockquote:after, +q:before, q:after { + content: ""; +} +blockquote, q { + quotes: "" ""; +} diff --git a/public/css/local/screen.css b/public/css/local/screen.css new file mode 100644 index 0000000..d6c9544 --- /dev/null +++ b/public/css/local/screen.css @@ -0,0 +1,101 @@ +/** + * Basic HTML element styles + */ +body { font-family:sans-serif; } + +h2 { font-size:131%; font-weight:bold; margin:.5em 0; color:#036; } +h3 { font-size:123.1%; font-weight:bold; margin:.5em 0 .25em 0; } +h4 { font-size:100%; font-weight:bold; } +a { text-decoration:none; color:#00f; } +p { margin:0 .5em .5em .5em; } + +table { margin:0 .5em .5em .5em; } +th { color:#333; font-weight:bold; font-size:90%; padding:0.25em; } +td { padding:.25em; } +thead th { text-align:left; } +tbody th { text-align:right; } + +ul { list-style-type:none; margin-left:1em; padding:0; } +li { margin:0; } + +fieldset { padding:.25em 0; } +legend { font-weight:bold; } +label { font-weight:bold; } + +/** + * Base styles for buttons and button links + */ +button, .button { + border:1px solid black; border-radius:6px; + display:inline-block; + padding:0 10px; + font-weight:bold; color:black; + background: linear-gradient(to bottom, #f5f6f6 0%,#dbdce2 21%,#b8bac6 49%,#dddfe3 80%,#f5f6f6 100%); +} + +/** + * Banner + */ +header { color:#fff; background-color:#036; margin:0; } +header a { color:#fff; font-weight:bold; } +header h1 { margin:0 4px; font-size:174%; } +header div { margin:4px; } +header nav { + margin-top:5px; padding:5px; + background-color:#fff; + border-top:2px solid #000; border-bottom:2px solid #000; +} +header nav a { font-weight:bold; color:black; margin-right:1em; } +#utilityBar { float:right; width:50%; text-align:right; } +#utilityBar li { display:inline; margin-right:1em; color:white; } + +/** + * Side Panel + */ +#panel-one nav { + border:2px solid #000; margin-bottom:0.5em; + border-radius:10px; + overflow:hidden; +} +#panel-one h2 { + background-color:#36c; color:#fff; + border-bottom:2px solid #000; + margin:0; padding:.25em; +} +#panel-one ul { margin:.25em; padding:0; } +#panel-one a { font-weight:bold; color:#000; } + +/** + * Main Content + */ +#errorMessages { background-color:#fcc; padding:4px; border-radius:10px; } +#errorMessages h2 { } + +#burialLinks td { vertical-align:middle; } +#aboutCemeteries { float:left; width:205px; } +#aboutCemeteries ul {padding:0;} +#cemeteryImages { float:right; width:200px; } + +.pageNavigation ul { list-style-type:none; } +.pageNavigation li { display:inline; margin-right:1em; } +.pageNavigation .current { border:2px solid green; } + +.searchInterment th { text-align:left; width:75px; } + +table { margin:5px 0; overflow:auto; } +tr { } +td label { font-weight:normal; color:#666666; } +td { padding:4px 4px 2px 4px; vertical-align:top; border:0; } +thead th { + font-weight:normal; color:#666666; text-align:left; + vertical-align:bottom; height:8pt; padding:4px 4px 2px 2px; +} +tbody th { + font-weight:normal; color:#666666; text-align:right; + height:8pt; padding:4px 4px 2px 2px; +} +th a:link,th a:visited { color:#3366cc; background-color:inherit; } +form table { border:none; } + +a.sorting { } + diff --git a/public/index.php b/public/index.php new file mode 100644 index 0000000..3d11a32 --- /dev/null +++ b/public/index.php @@ -0,0 +1,40 @@ + + */ +include '../configuration.inc'; +use Blossom\Classes\Template; +use Blossom\Classes\Block; + +// Check for routes +if (preg_match('|'.BASE_URI.'(/([a-zA-Z0-9]+))?(/([a-zA-Z0-9]+))?|',$_SERVER['REQUEST_URI'],$matches)) { + $resource = isset($matches[2]) ? $matches[2] : 'index'; + $action = isset($matches[4]) ? $matches[4] : 'index'; +} + +// Create the default Template +$template = !empty($_REQUEST['format']) + ? new Template('default',$_REQUEST['format']) + : new Template('default'); + +// Execute the Controller::action() +if (isset($resource) && isset($action) && $ZEND_ACL->hasResource($resource)) { + $USER_ROLE = isset($_SESSION['USER']) ? $_SESSION['USER']->getRole() : 'Anonymous'; + if ($ZEND_ACL->isAllowed($USER_ROLE, $resource, $action)) { + $controller = 'Application\Controllers\\'.ucfirst($resource).'Controller'; + $c = new $controller($template); + $c->$action(); + } + else { + header('HTTP/1.1 403 Forbidden', true, 403); + $_SESSION['errorMessages'][] = new \Exception('noAccessAllowed'); + } +} +else { + header('HTTP/1.1 404 Not Found', true, 404); + $template->blocks[] = new Block('404.inc'); +} + +echo $template->render(); diff --git a/templates/html/partials/banner.inc b/templates/html/partials/banner.inc index 5d5ef23..ea568d1 100644 --- a/templates/html/partials/banner.inc +++ b/templates/html/partials/banner.inc @@ -1,18 +1,32 @@ - + + diff --git a/templates/html/partials/header.inc b/templates/html/partials/header.inc index 263507d..c2a5cfe 100644 --- a/templates/html/partials/header.inc +++ b/templates/html/partials/header.inc @@ -3,11 +3,8 @@ - - Cemeteries + + + + <?php echo isset($this->title) ? self::escape($this->title) : 'Cemeteries'; ?> diff --git a/templates/html/partials/menubar.inc b/templates/html/partials/menubar.inc index fb821c8..6d46d8c 100644 --- a/templates/html/partials/menubar.inc +++ b/templates/html/partials/menubar.inc @@ -1,18 +1,21 @@ - + + diff --git a/templates/html/two-column.inc b/templates/html/two-column.inc index f76ce4d..f5a78dd 100644 --- a/templates/html/two-column.inc +++ b/templates/html/two-column.inc @@ -1,34 +1,30 @@ - + layout = 'two-column'; - $dir = dirname(__FILE__); - include $dir.'/partials/header.inc'; + $this->layout = 'two-column'; + include __DIR__.'/partials/header.inc'; ?> - - -
- -
- includeBlocks(); - ?> -
-
- + +
+ +
+ includeBlocks(); + ?> +
+
+