Skip to content

Commit

Permalink
Merge pull request #1 from Alanaktion/master
Browse files Browse the repository at this point in the history
Update
  • Loading branch information
Supme committed Nov 12, 2014
2 parents 8c59493 + d2fe3ec commit df44f0d
Show file tree
Hide file tree
Showing 168 changed files with 10,997 additions and 11,977 deletions.
5 changes: 1 addition & 4 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,2 @@
.idea/
plugin
config.ini
Thumbs.db
lib/api/
nbproject/
38 changes: 5 additions & 33 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,40 +1,12 @@
[![Gitter](https://badges.gitter.im/Join Chat.svg)](https://gitter.im/Alanaktion/phproject?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
Phproject
===========
*A lightweight project management system in PHP*


### Requirements
- PHP 5.3.3 or later (5.4/5.5 recommended)
- bcrypt extension
- PDO extension
- GD extension
- MySQL/MariaDB server
- Web server with support for URL rewrites (Apache .htaccess file and nginx sample configuration included)
*A high-performance project management system in PHP*

### Installation
1. Create a database on your MySQL server
2. Import the database.sql file into your new database
1. a user named "admin" with the password "admin" will be created automatically
3. Copy config-base.ini to config.ini
4. Update config.ini with your database connection details
5. Ensure the tmp/, tmp/cache/, and log/ directories exist and are writable by the web server

### Additional setup
- DEBUG in config.ini supports levels 0-3, with 3 being the most verbose. You should always use 0 in a production environment!
- Phproject is fast, but you can significantly increase performance by installing an op code caching layer like APC. Using APC also greatly increases the speed of temporary cached data, including minified code and common database queries.

### Updating
Simply pulling the repo again should be safe for updates. If database.sql has been modified, you will need to merge the changes into your database as Phproject doesn't yet have a database upgrade system built in. If something breaks after updating, clearing the APC cache or the tmp/ and tmp/cache/ directories of everything except .gitignore will usually solve the problem.

### Customization
Phproject's UI is built around [Twitter Bootstrap 3](http://getbootstrap.com), and is compatible with customized Bootstrap styles including Bootswatch. Simply change the site.theme entry in config.ini to the web path of a Bootstrap CSS file and it will replace the main CSS. Phproject's additions to the Bootstrap core are designed to add features without breaking any existing components, so unless your customized Bootstrap is very heavily modified, everything should continue to work consistently.

To give your site a custom title and meta description, update the site.name and site.description entries in config.ini.

You can also customize the default user image that is shown when a user does not have a Gravatar (Phproject uses mm/mysterman by default) as well as the maximum content rating of Gravatars to show (pg by default). The gravatar.default and gravatar.rating entries in config.ini can be updated to change these.
Simply clone the repo into a web accessible directory, go to the page in a browser, and fill in your database connection details.

### Internal details
Phproject uses the [Fat Free Framework](http://fatfreeframework.com/home) as it's base, allowing it to have a simple but powerful feature set without compromising performance. Every template file is compiled at run time, and only needs to be recompiled when the code is changed. Phproject includes internal caching that prevents duplicate or bulk database queries from being used, greatly improving performance on large pages with lots of data. This caching will only work if the tmp/ directory is writeable or APC is installed and configured on the server.
Detailed requirements and installation instructions are available at [phproject.org](http://www.phproject.org/install.html).

### Contributing
Phproject is maintained as an open source project for use by anyone around the world. If you find a bug or would like to see a new feature added, feel free to [create an issue on Github](https://github.com/Alanaktion/phproject/issues/new) or [submit a pull request](https://github.com/Alanaktion/phproject/compare/) with new code.
Phproject is maintained as an open source project for use by anyone around the world under the [GNU General Public License](http://www.gnu.org/licenses/gpl-3.0.txt). If you find a bug or would like a new feature added, [open an issue](https://github.com/Alanaktion/phproject/issues/new) or [submit a pull request](https://github.com/Alanaktion/phproject/compare/) with new code.
35 changes: 32 additions & 3 deletions app/controller/base.php → app/controller.php
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
<?php

namespace Controller;

abstract class Base {
abstract class Controller {

/**
* Require a user to be logged in. Redirects to /login if a session is not found.
Expand Down Expand Up @@ -40,4 +38,35 @@ protected function _requireAdmin() {
}
}

/**
* Render a view
* @param string $file
* @param string $mime
* @param array $hive
* @param integer $ttl
*/
protected function _render($file, $mime = "text/html", array $hive = null, $ttl = 0) {
echo \Helper\View::instance()->render($file, $mime, $hive, $ttl);
}

/**
* Output object as JSON and set appropriate headers
* @param mixed $object
*/
protected function _printJson($object) {
if(!headers_sent()) {
header("Content-type: application/json");
}
echo json_encode($object);
}

/**
* Get current time and date in a MySQL NOW() format
* @param boolean $time Whether to include the time in the string
* @return string
*/
function now($time = true) {
return $time ? date("Y-m-d H:i:s") : date("Y-m-d");
}

}
48 changes: 24 additions & 24 deletions app/controller/admin.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace Controller;

class Admin extends Base {
class Admin extends \Controller {

protected $_userId;

Expand Down Expand Up @@ -37,7 +37,7 @@ public function index($f3, $params) {

$f3->set("db_stats", $db->exec("SHOW STATUS WHERE Variable_name LIKE 'Delayed_%' OR Variable_name LIKE 'Table_lock%' OR Variable_name = 'Uptime'"));

echo \Template::instance()->render("admin/index.html");
$this->_render("admin/index.html");
}

public function users($f3, $params) {
Expand All @@ -47,7 +47,7 @@ public function users($f3, $params) {
$users = new \Model\User();
$f3->set("users", $users->find("deleted_date IS NULL AND role != 'group'"));

echo \Template::instance()->render("admin/users.html");
$this->_render("admin/users.html");
}

public function user_edit($f3, $params) {
Expand Down Expand Up @@ -75,7 +75,7 @@ public function user_edit($f3, $params) {
}
}
$f3->set("this_user", $user);
echo \Template::instance()->render("admin/users/edit.html");
$this->_render("admin/users/edit.html");
} else {
$f3->error(404, "User does not exist.");
}
Expand All @@ -97,7 +97,7 @@ public function user_new($f3, $params) {
$user->api_key = $security->salt_sha1();
$user->role = $f3->get("POST.role");
$user->task_color = ltrim($f3->get("POST.task_color"), "#");
$user->created_date = now();
$user->created_date = $this->now();
$user->save();
if($user->id) {
$f3->reroute("/admin/users#" . $user->id);
Expand All @@ -107,7 +107,7 @@ public function user_new($f3, $params) {
} else {
$f3->set("title", "Add User");
$f3->set("rand_color", sprintf("#%06X", mt_rand(0, 0xFFFFFF)));
echo \Template::instance()->render("admin/users/new.html");
$this->_render("admin/users/new.html");
}
}

Expand All @@ -117,7 +117,7 @@ public function user_delete($f3, $params) {
$user->delete();

if($f3->get("AJAX")) {
print_json(array("deleted" => 1));
$this->_printJson(array("deleted" => 1));
} else {
$f3->reroute("/admin/users");
}
Expand All @@ -144,7 +144,7 @@ public function groups($f3, $params) {
}
$f3->set("groups", $group_array);

echo \Template::instance()->render("admin/groups.html");
$this->_render("admin/groups.html");
}

public function group_new($f3, $params) {
Expand All @@ -156,7 +156,7 @@ public function group_new($f3, $params) {
$group->name = $f3->get("POST.name");
$group->role = "group";
$group->task_color = sprintf("%06X", mt_rand(0, 0xFFFFFF));
$group->created_date = now();
$group->created_date = $this->now();
$group->save();
$f3->reroute("/admin/groups");
} else {
Expand All @@ -178,15 +178,15 @@ public function group_edit($f3, $params) {
$users = new \Model\User();
$f3->set("users", $users->find("deleted_date IS NULL AND role != 'group'", array("order" => "name ASC")));

echo \Template::instance()->render("admin/groups/edit.html");
$this->_render("admin/groups/edit.html");
}

public function group_delete($f3, $params) {
$group = new \Model\User();
$group->load($params["id"]);
$group->delete();
if($f3->get("AJAX")) {
print_json(array("deleted" => 1));
$this->_printJson(array("deleted" => 1));
} else {
$f3->reroute("/admin/groups");
}
Expand Down Expand Up @@ -223,12 +223,12 @@ public function group_ajax($f3, $params) {
$user_group = new \Model\User\Group();
$user_group->load(array("user_id = ? AND group_id = ?", $f3->get("POST.user_id"), $f3->get("POST.group_id")));
$user_group->delete();
print_json(array("deleted" => 1));
$this->_printJson(array("deleted" => 1));
break;
case "change_title":
$group->name = trim($f3->get("POST.name"));
$group->save();
print_json(array("changed" => 1));
$this->_printJson(array("changed" => 1));
break;
}
}
Expand Down Expand Up @@ -258,7 +258,7 @@ public function attributes($f3, $params) {
$attributes = new \Model\Attribute();
$f3->set("attributes", $attributes->find());

echo \Template::instance()->render("admin/attributes.html");
$this->_render("admin/attributes.html");
}

public function attribute_new($f3, $params) {
Expand All @@ -279,7 +279,7 @@ public function attribute_new($f3, $params) {
}
}

echo \Template::instance()->render("admin/attributes/edit.html");
$this->_render("admin/attributes/edit.html");
}

public function attribute_edit($f3, $params) {
Expand All @@ -291,7 +291,7 @@ public function attribute_edit($f3, $params) {
$attr->load($params["id"]);
$f3->set("attribute", $attr);

echo \Template::instance()->render("admin/attributes/edit.html");
$this->_render("admin/attributes/edit.html");
}

public function sprints($f3, $params) {
Expand All @@ -301,7 +301,7 @@ public function sprints($f3, $params) {
$sprints = new \Model\Sprint();
$f3->set("sprints", $sprints->find());

echo \Template::instance()->render("admin/sprints.html");
$this->_render("admin/sprints.html");
}

public function sprint_new($f3, $params) {
Expand All @@ -311,7 +311,7 @@ public function sprint_new($f3, $params) {
if($post = $f3->get("POST")) {
if(empty($post["start_date"]) || empty($post["end_date"])) {
$f3->set("error", "Start and end date are required");
echo \Template::instance()->render("admin/sprints/new.html");
$this->_render("admin/sprints/new.html");
return;
}

Expand All @@ -320,7 +320,7 @@ public function sprint_new($f3, $params) {

if($end <= $start) {
$f3->set("error", "End date must be after start date");
echo \Template::instance()->render("admin/sprints/new.html");
$this->_render("admin/sprints/new.html");
return;
}

Expand All @@ -333,7 +333,7 @@ public function sprint_new($f3, $params) {
return;
}

echo \Template::instance()->render("admin/sprints/new.html");
$this->_render("admin/sprints/new.html");
}

//new function here!!!
Expand All @@ -353,7 +353,7 @@ public function sprint_edit($f3, $params) {
if($post = $f3->get("POST")) {
if(empty($post["start_date"]) || empty($post["end_date"])) {
$f3->set("error", "Start and end date are required");
echo \Template::instance()->render("admin/sprints/edit.html");
$this->_render("admin/sprints/edit.html");
return;
}

Expand All @@ -362,7 +362,7 @@ public function sprint_edit($f3, $params) {

if($end <= $start) {
$f3->set("error", "End date must be after start date");
echo \Template::instance()->render("admin/sprints/edit.html");
$this->_render("admin/sprints/edit.html");
return;
}

Expand All @@ -376,13 +376,13 @@ public function sprint_edit($f3, $params) {
}
$f3->set("sprint", $sprint);

echo \Template::instance()->render("admin/sprints/edit.html");
$this->_render("admin/sprints/edit.html");
}

public function sprint_breaker($f3, $params) {
$f3->set("title", "SprintBreaker");
$f3->set("menuitem", "admin");

echo \Template::instance()->render("admin/sprints/breaker.html");
$this->_render("admin/sprints/breaker.html");
}
}
41 changes: 26 additions & 15 deletions app/controller/api/base.php → app/controller/api.php
Original file line number Diff line number Diff line change
@@ -1,11 +1,32 @@
<?php

namespace Controller\Api;
namespace Controller;

abstract class Base extends \Controller\Base {
abstract class Api extends \Controller {

protected $_userId;

function __construct() {
$f3 = \Base::instance();
$f3->set("ONERROR", function(\Base $f3) {
if(!headers_sent()) {
header("Content-type: application/json");
}
$out = array(
"status" => $f3->get("ERROR.code"),
"error" => $f3->get("ERROR.text")
);
if($f3->get("DEBUG") >= 2) {
$out["trace"] = $f3->get("ERROR.trace");
}
echo json_encode($out);
});

$this->_userId = $this->_requireAuth();
}

/**
* Require an API key. Sends an HTTP 403 if one is not supplied.
* Require an API key. Sends an HTTP 401 if one is not supplied.
* @return int|bool
*/
protected function _requireAuth() {
Expand All @@ -27,6 +48,8 @@ protected function _requireAuth() {
$key = $f3->get("HEADERS.X-Redmine-API-Key");
} elseif($f3->get("HEADERS.X-API-Key")) {
$key = $f3->get("HEADERS.X-API-Key");
} elseif($f3->get("HEADERS.X-Api-Key")) {
$key = $f3->get("HEADERS.X-Api-Key");
}

$user->load(array("api_key", $key));
Expand All @@ -37,20 +60,8 @@ protected function _requireAuth() {
return $user->id;
} else {
$f3->error(401);
$f3->unload();
return false;
}
}

/**
* Output an error in a JSON object, stop execution
* @param integer $message
*/
protected function _error($message = 1) {
print_json(array(
"error" => $message
));
exit();
}

}
Loading

0 comments on commit df44f0d

Please sign in to comment.