Compare commits

...

20 Commits

Author SHA1 Message Date
Sven Slootweg 6f9e4ccc8d Add salt key to default configuration 7 years ago
Sven Slootweg 8854947866 Display a regular 404 error when a project does not exist 7 years ago
Sven Slootweg 9456a01c34 Tweak ticket display 9 years ago
Sven Slootweg 724dec5a61 Actually get ticket data from the database 9 years ago
Sven Slootweg 21da4e580f Move ticket response date to the right hand side 9 years ago
Sven Slootweg 3f0728b945 Create a fance 404 page :) 9 years ago
Sven Slootweg 08b7a7d825 Basic design for ticket lookup page 9 years ago
Sven Slootweg d6588b6f1a Fix constants, output tickets from database, and implement status/priority names for Ticket objects 9 years ago
Sven Slootweg 853bb50ab6 Fix license notice 9 years ago
Sven Slootweg 30de910e73 Fix license notice, make ticket rows clickable, and get data from variables 9 years ago
Sven Slootweg 5bf96a8d02 Add clickable styles and reorganize stylesheet 9 years ago
Sven Slootweg 73310dbbdc Make minor changes to color scheme 9 years ago
Sven Slootweg 0fe01a0336 Add 'new' ticket status for unreviewed tickets 9 years ago
Sven Slootweg 1bdc620153 Some first attempts at a ticket list color scheme and page layout 9 years ago
Sven Slootweg 3ac9274b1f Return a 404 error when a page does not exist 9 years ago
Sven Slootweg a597290a01 Make routing code a lot cleaner and less repetitive 9 years ago
Sven Slootweg c28cecd570 Whoops, capitalization mistake 9 years ago
Sven Slootweg c2e374964a Fix project-not-found page and project URLs 9 years ago
Sven Slootweg 3dc8c8b08a Add some stuff, remove active config.json from tracked files, update config 9 years ago
Sven Slootweg 48b4b80447 Progress... 9 years ago
  1. 1
      .gitignore
  2. 18
      config.json.example
  3. 28
      public_html/authenticators/project.php
  4. 2
      public_html/classes/logentry.php
  5. 3
      public_html/classes/project.php
  6. 63
      public_html/classes/ticket.php
  7. 95
      public_html/classes/ticketmessage.php
  8. 13
      public_html/debug.createuser.php
  9. 2
      public_html/include/base.php
  10. 19
      public_html/include/constants.php
  11. 24
      public_html/index.php
  12. 17
      public_html/modules/error/404.php
  13. 16
      public_html/modules/home/index.php
  14. 27
      public_html/modules/project/index.php
  15. 44
      public_html/modules/project/tickets/index.php
  16. 77
      public_html/modules/project/tickets/view.php
  17. 96
      public_html/rewrite.php
  18. 156
      public_html/static/404.js
  19. 1456
      public_html/static/engine.js
  20. 4
      public_html/static/jquery.js
  21. 42
      public_html/static/script.js
  22. 316
      public_html/static/style.css
  23. 10
      public_html/templates/error/404.tpl
  24. 13
      public_html/templates/home/layout.tpl
  25. 72
      public_html/templates/layout.tpl
  26. 51
      public_html/templates/project/index.tpl
  27. 19
      public_html/templates/project/layout.tpl
  28. 18
      public_html/templates/project/tickets/index.tpl
  29. 58
      public_html/templates/project/tickets/view.tpl

1
.gitignore

@ -0,0 +1 @@
config.json

18
config.json → config.json.example

@ -1,6 +1,7 @@
{
"database": {
"driver": "mysql",
"pdo": true,
"hostname": "localhost",
"username": "root",
"password": "",
@ -19,14 +20,19 @@
"port": 11211
},
"class_map": {
"user": "User",
"interestgroup": "InterestGroup",
"project": "Project",
"repository": "Repository",
"ticket": "Ticket"
"user": "User",
"interestgroup": "InterestGroup",
"project": "Project",
"repository": "Repository",
"ticket": "Ticket",
"tickettag": "TicketTag",
"ticketmessage": "TicketMessage",
"ticketattachment": "TicketAttachment",
"logentry": "LogEntry"
},
"components": [
"router",
"errorhandler"
]
],
"salt": "abcdef"
}

28
public_html/authenticators/project.php

@ -0,0 +1,28 @@
<?php
/*
* Cryto Team is more free software. It is licensed under the WTFPL, which
* allows you to do pretty much anything with it, without having to
* ask permission. Commercial use is allowed, and no attribution is
* required. We do politely request that you share your modifications
* to benefit other developers, but you are under no enforced
* obligation to do so :)
*
* Please read the accompanying LICENSE document for the full WTFPL
* licensing text.
*/
if(!isset($_APP)) { die("Unauthorized."); }
$uSlug = $router->uParameters[1];
try
{
$sProject = Project::CreateFromQuery("SELECT * FROM projects WHERE `Slug` = :Slug", array(":Slug" => $uSlug), 0, true);
NewTemplater::SetGlobalVariable("project-name", $sProject->sName);
NewTemplater::SetGlobalVariable("project-url", "/project/{$sProject->sSlug}");
$sRouterAuthenticated = true;
}
catch (NotFoundException $e)
{
throw new RouterException("Project does not exist");
}

2
public_html/classes/logentry.php

@ -1,6 +1,6 @@
<?php
/*
* projectname is more free software. It is licensed under the WTFPL, which
* Cryto Team is more free software. It is licensed under the WTFPL, which
* allows you to do pretty much anything with it, without having to
* ask permission. Commercial use is allowed, and no attribution is
* required. We do politely request that you share your modifications

3
public_html/classes/project.php

@ -23,6 +23,9 @@ class Project extends CPHPDatabaseRecordClass
'string' => array(
'Name' => "Name",
'ShortDescription' => "ShortDescription",
'Slug' => "Slug"
),
'simplehtml' => array(
'LongDescription' => "LongDescription"
),
'numeric' => array(

63
public_html/classes/ticket.php

@ -25,17 +25,76 @@ class Ticket extends CPHPDatabaseRecordClass
),
'numeric' => array(
'Status' => "Status",
'CreatorId' => "UserId",
'CreatorId' => "CreatorId",
'OwnerId' => "OwnerId",
'Priority' => "Priority",
'ProjectId' => "ProjectId"
),
"timestamp" => array(
'CreationDate' => "CreationDate"
),
'user' => array(
'Creator' => "UserId",
'Creator' => "CreatorId",
'Owner' => "OwnerId"
),
'project' => array(
'Project' => "ProjectId"
)
);
public function __get($name)
{
switch($name)
{
case "sStatusName":
return $this->GetStatusName();
break;
case "sPriorityName":
return $this->GetPriorityName();
break;
default:
return parent::__get($name);
break;
}
}
public function GetStatusName()
{
switch($this->sStatus)
{
case NEWTICKET:
return "New";
case OPEN:
return "Open";
case CLOSED:
return "Closed";
case INVALID:
return "Invalid";
case NEEDS_REVIEW:
return "Needs Review";
case IN_PROGRESS:
return "In Progress";
default:
return "Unknown";
}
}
public function GetPriorityName()
{
switch($this->sPriority)
{
case PRIORITY_LOWEST:
return "Lowest";
case PRIORITY_LOW:
return "Low";
case PRIORITY_NORMAL:
return "Normal";
case PRIORITY_HIGH:
return "High";
case PRIORITY_CRITICAL:
return "Critical";
default:
return "Unknown";
}
}
}

95
public_html/classes/ticketmessage.php

@ -20,7 +20,7 @@ class TicketMessage extends CPHPDatabaseRecordClass
public $verify_query = "SELECT * FROM ticket_messages WHERE `Id` = :Id";
public $prototype = array(
'string' => array(
'simplehtml' => array(
'Body' => "Body"
),
'boolean' => array(
@ -34,6 +34,9 @@ class TicketMessage extends CPHPDatabaseRecordClass
'timestamp' => array(
'Date' => "Date"
),
'boolean' => array(
'IsEvent' => "Event"
),
'user' => array(
'Author' => "UserId"
),
@ -44,4 +47,94 @@ class TicketMessage extends CPHPDatabaseRecordClass
'Project' => "ProjectId"
)
);
public function __get($name)
{
switch($name)
{
case "sComponent":
return $this->GetComponentName();
break;
case "sOperation":
return $this->GetOperationName();
break;
default:
return parent::__get($name);
break;
}
}
private function UnpackEvent()
{
if(empty($this->uEventData))
{
$this->uEventData = json_decode($this->uBody);
}
}
public function GetComponentName()
{
$this->UnpackEvent();
switch($this->uEventData->component)
{
case STATUS:
return "status";
case PRIORITY:
return "priority";
case OWNER:
return "owner";
default:
return "unknown";
}
}
public function GetOperationName()
{
$this->UnpackEvent();
if($this->uEventData->component == OWNER)
{
$sEventUser = new User($this->uEventData->operation);
return $sEventUser->sDisplayName;
}
elseif($this->uEventData->component == PRIORITY)
{
switch($this->uEventData->operation)
{
case PRIORITY_LOWEST:
return "Lowest";
case PRIORITY_LOW:
return "Low";
case PRIORITY_NORMAL:
return "Normal";
case PRIORITY_HIGH:
return "High";
case PRIORITY_CRITICAL:
return "Critical";
default:
return "Unknown";
}
}
elseif($this->uEventData->component == STATUS)
{
switch($this->uEventData->operation)
{
case NEWTICKET:
return "New";
case OPEN:
return "Open";
case CLOSED:
return "Closed";
case INVALID:
return "Invalid";
case NEEDS_REVIEW:
return "Needs Review";
case IN_PROGRESS:
return "In Progress";
default:
return "Unknown";
}
}
}
}

13
public_html/debug.createuser.php

@ -0,0 +1,13 @@
<?php
require("include/base.php");
$sUser = new User(0);
$sUser->uUsername = "test";
$sUser->uPassword = "test";
$sUser->uDisplayName = "Test user";
$sUser->uEmailAddress = "test@test.com";
$sUser->uIsActivated = true;
$sUser->uIsAdmin = true;
$sUser->GenerateSalt();
$sUser->GenerateHash();
$sUser->InsertIntoDatabase();

2
public_html/include/base.php

@ -5,6 +5,8 @@ require("cphp/base.php");
$_APP = true;
require("constants.php");
function __autoload($class_name)
{
global $_APP;

19
public_html/include/constants.php

@ -16,15 +16,20 @@ if(!isset($_APP)) { die("Unauthorized."); }
$constants = array(
"PRIORITY_LOWEST" => 1,
"PRIORITY_LOW" => 2,
"PRIORITY_MEDIUM" => 3,
"PRIORITY_NORMAL" => 3,
"PRIORITY_HIGH" => 4,
"PRIORITY_CRITICAL" => 5,
"OPEN" => 1,
"CLOSED" => 2,
"INVALID" => 3,
"NEEDS_REVIEW" => 4,
"IN_PROGRESS" => 5
"NEWTICKET" => 1,
"OPEN" => 2,
"CLOSED" => 3,
"INVALID" => 4,
"NEEDS_REVIEW" => 5,
"IN_PROGRESS" => 6,
"STATUS" => 1,
"PRIORITY" => 2,
"OWNER" => 3,
"ATTACHMENT_FILE" => 1,
"ATTACHMENT_COMMIT" => 2,
@ -40,7 +45,7 @@ $constants = array(
"COMMIT" => 4,
"FORUMPOST" => 5,
"INVITATION" => 6,
"DESCRIPTION" => 7
"DESCRIPTION" => 7,
"CREATE" => 1,
"DELETE" => 2,

24
public_html/index.php

@ -1,14 +1,14 @@
<?php
require("include/base.php");
/*
* Cryto Team is more free software. It is licensed under the WTFPL, which
* allows you to do pretty much anything with it, without having to
* ask permission. Commercial use is allowed, and no attribution is
* required. We do politely request that you share your modifications
* to benefit other developers, but you are under no enforced
* obligation to do so :)
*
* Please read the accompanying LICENSE document for the full WTFPL
* licensing text.
*/
echo(Templater::AdvancedParse("layout", $locale->strings, array(
"project-name" => "Demo project",
"long-description" => "A large, multi-paragraph description of the project would go here.",
"no-downloads" => false,
"stable-version" => "1.5.3",
"experimental-version" => "1.6.1",
"line-count" => "62,671",
"ticket-count" => 12,
"tickets" => array(),
"more-tickets" => false
)));
require("rewrite.php");

17
public_html/modules/error/404.php

@ -0,0 +1,17 @@
<?php
/*
* Cryto Team is more free software. It is licensed under the WTFPL, which
* allows you to do pretty much anything with it, without having to
* ask permission. Commercial use is allowed, and no attribution is
* required. We do politely request that you share your modifications
* to benefit other developers, but you are under no enforced
* obligation to do so :)
*
* Please read the accompanying LICENSE document for the full WTFPL
* licensing text.
*/
if(!isset($_APP)) { die("Unauthorized."); }
http_status_code(404);
$sPageContents = NewTemplater::Render("error/404", $locale->strings, array());

16
public_html/modules/home/index.php

@ -0,0 +1,16 @@
<?php
/*
* Cryto Team is more free software. It is licensed under the WTFPL, which
* allows you to do pretty much anything with it, without having to
* ask permission. Commercial use is allowed, and no attribution is
* required. We do politely request that you share your modifications
* to benefit other developers, but you are under no enforced
* obligation to do so :)
*
* Please read the accompanying LICENSE document for the full WTFPL
* licensing text.
*/
if(!isset($_APP)) { die("Unauthorized."); }
$sPageContents = "hi";

27
public_html/modules/project/index.php

@ -0,0 +1,27 @@
<?php
/*
* Cryto Team is more free software. It is licensed under the WTFPL, which
* allows you to do pretty much anything with it, without having to
* ask permission. Commercial use is allowed, and no attribution is
* required. We do politely request that you share your modifications
* to benefit other developers, but you are under no enforced
* obligation to do so :)
*
* Please read the accompanying LICENSE document for the full WTFPL
* licensing text.
*/
if(!isset($_APP)) { die("Unauthorized."); }
$sPageTitle = "Overview";
$sCurrentPage = "overview";
$sPageContents = Templater::AdvancedParse("project/index", $locale->strings, array(
"long-description" => $sProject->sLongDescription,
"no-downloads" => false,
"stable-version" => "1.5.3",
"experimental-version" => "1.6.1",
"line-count" => "62,671",
"ticket-count" => 12,
"tickets" => array(),
"more-tickets" => false
));

44
public_html/modules/project/tickets/index.php

@ -0,0 +1,44 @@
<?php
/*
* Cryto Team is more free software. It is licensed under the WTFPL, which
* allows you to do pretty much anything with it, without having to
* ask permission. Commercial use is allowed, and no attribution is
* required. We do politely request that you share your modifications
* to benefit other developers, but you are under no enforced
* obligation to do so :)
*
* Please read the accompanying LICENSE document for the full WTFPL
* licensing text.
*/
if(!isset($_APP)) { die("Unauthorized."); }
$sPageTitle = "Tickets";
$sCurrentPage = "tickets";
$sTickets = array();
try
{
$result = Ticket::CreateFromQuery("SELECT * FROM tickets WHERE `ProjectId` = :ProjectId", array(":ProjectId" => $sProject->sId));
}
catch (NotFoundException $e)
{
$result = array();
}
foreach($result as $sTicket)
{
$sTickets[] = array(
"id" => $sTicket->sId,
"title" => $sTicket->sSubject,
"priority" => $sTicket->sPriorityName,
"priority-lowercase" => strtolower($sTicket->sPriorityName),
"status" => $sTicket->sStatusName,
"status-lowercase" => strtolower($sTicket->sStatusName)
);
}
$sPageContents = NewTemplater::Render("project/tickets/index", $locale->strings, array(
"tickets" => $sTickets
));

77
public_html/modules/project/tickets/view.php

@ -0,0 +1,77 @@
<?php
/*
* Cryto Team is more free software. It is licensed under the WTFPL, which
* allows you to do pretty much anything with it, without having to
* ask permission. Commercial use is allowed, and no attribution is
* required. We do politely request that you share your modifications
* to benefit other developers, but you are under no enforced
* obligation to do so :)
*
* Please read the accompanying LICENSE document for the full WTFPL
* licensing text.
*/
if(!isset($_APP)) { die("Unauthorized."); }
$sCurrentPage = "tickets";
try
{
$sTicket = new Ticket($router->uParameters[2]);
$sInitialMessage = TicketMessage::CreateFromQuery("SELECT * FROM ticket_messages WHERE `TicketId` = :TicketId AND `FirstMessage` = 1",
array(":TicketId" => $sTicket->sId), 0, true);
$sUpdates = array();
try
{
$result = TicketMessage::CreateFromQuery("SELECT * FROM ticket_messages WHERE `TicketId` = :TicketId AND `FirstMessage` = 0 ORDER BY `Date` ASC",
array(":TicketId" => $sTicket->sId), 0);
}
catch (NotFoundException $e)
{
$result = array();
}
foreach($result as $sMessage)
{
if($sMessage->sIsEvent)
{
$uEventData = json_decode($sMessage->uBody);
$sUpdates[] = array(
"event" => true,
"user" => $sMessage->sAuthor->sDisplayName,
"component" => $sMessage->sComponent,
"operation" => $sMessage->sOperation,
"date" => time_ago($sMessage->sDate, $locale)
);
}
else
{
$sUpdates[] = array(
"event" => false,
"author" => $sMessage->sAuthor->sDisplayName,
"body" => $sMessage->sBody,
"date" => time_ago($sMessage->sDate, $locale)
);
}
}
$sPageContents = NewTemplater::Render("project/tickets/view", $locale->strings, array(
"title" => $sTicket->sSubject,
"priority" => $sTicket->sPriorityName,
"status" => $sTicket->sStatusName,
"owner" => $sTicket->sOwner->sDisplayName,
"creator" => $sTicket->sCreator->sDisplayName,
"date" => local_from_unix($sTicket->sCreationDate, $locale->datetime_long),
"body" => $sInitialMessage->sBody,
"updates" => $sUpdates
));
}
catch (NotFoundException $e)
{
pretty_dump($e);
require("modules/error/404.php");
}

96
public_html/rewrite.php

@ -0,0 +1,96 @@
<?php
/*
* Cryto Team is more free software. It is licensed under the WTFPL, which
* allows you to do pretty much anything with it, without having to
* ask permission. Commercial use is allowed, and no attribution is
* required. We do politely request that you share your modifications
* to benefit other developers, but you are under no enforced
* obligation to do so :)
*
* Please read the accompanying LICENSE document for the full WTFPL
* licensing text.
*/
require("include/base.php");
$sPageTitle = "";
$sPageContents = "";
$sCurrentPage = "";
/* Define the different routes for the application */
$routes = array(
"home" => array(
"^/$" => "modules/home/index.php"
),
"project" => array(
"^/project/([a-zA-Z0-9_-]+)$" => "modules/project/index.php",
"^/project/([a-zA-Z0-9_-]+)/tickets$" => "modules/project/tickets/index.php",
"^/project/([a-zA-Z0-9_-]+)/ticket/([0-9]+)$" => "modules/project/tickets/view.php"
)
);
/* Define the preset values for the route "categories" */
$presets = array(
"home" => array(
"_page_type" => "home"
),
"project" => array(
"_page_type" => "project",
"authenticator" => "authenticators/project.php",
"auth_error" => ""
)
);
/* Generate a routing table */
$router = new CPHPRouter();
$router->allow_slash = true;
$router->ignore_query = true;
$router->routes = array(0 => array());
foreach($routes as $category => $items)
{
foreach($items as $route => $target)
{
$router->routes[0][$route] = $presets[$category];
$router->routes[0][$route]['target'] = $target;
}
}
/* Route the actual request */
try
{
$router->RouteRequest();
}
catch (RouterException $e)
{
require("modules/error/404.php");
}
/* Render the resulting page */
if(empty($router->uVariables['page_type']) || $router->uVariables['page_type'] == "home")
{
$sContents = NewTemplater::Render("home/layout", $locale->strings, array(
"contents" => $sPageContents
));
}
elseif($router->uVariables['page_type'] == "project")
{
$sContents = NewTemplater::Render("project/layout", $locale->strings, array(
"contents" => $sPageContents,
"current-page" => $sCurrentPage
));
}
else
{
die();
}
echo(NewTemplater::Render("layout", $locale->strings, array(
"contents" => $sContents
)));

156
public_html/static/404.js

@ -0,0 +1,156 @@
var engine;
$(function(){
engine = new Engine({
"enable_sound": false
});
loader = new engine.Preloader();
loader.Run({
onfinish: InitializeEffect
});
});
function InitializeEffect()
{
engine.AddItems({
objects: {
controller: {
grid_w: 60,
grid_h: 18,
tile_w: 16,
tile_h: 16,
numbers: [],
colored: [],
OnCreate: function(event){
for(var x = 0; x < this.grid_w; x++)
{
this.numbers[x] = [];
this.colored[x] = [];
}
this.RegenerateNumbers();
},
OnMouseMove: function(event){
this.SetMouse(event.x, event.y);
},
OnStep: function(event){
if(this.scene.step_counter % 15 == 0)
{
this.RegenerateNumbers();
return true;
}
},
OnDraw: function(event){
for(var x = 0; x < this.grid_w; x++)
{
for(var y = 0; y < this.grid_h; y++)
{
if(this.colored[x][y])
{
//var text = (this.colored[x][y]) ? "0" : this.numbers[x][y];
var text = this.numbers[x][y];
this.scene.DrawText(text, {
x: x * this.tile_w,
y: y * this.tile_h,
color: (this.colored[x][y]) ? "blue" : "silver"
});
}
}
}
},
RegenerateNumbers: function(){
for(var x = 0; x < this.grid_w; x++)
{
for(var y = 0; y < this.grid_h; y++)
{
this.numbers[x][y] = engine.Random.Choose(0, 1);
this.colored[x][y] = false;
}
}
this.ApplyMouse();
},
SetMouse: function(x, y){
this.mouse_x = x;
this.mouse_y = y;
this.ApplyMouse();
},
ApplyMouse: function(){
this.ClearColored();
var matrix_w = 9;
var matrix_h = 14;
var matrix = [
[0, 1, 1, 1, 1, 1, 1, 1, 1],
[0, 0, 1, 1, 1, 1, 1, 1, 1],
[0, 0, 0, 1, 1, 1, 1, 1, 1],
[0, 0, 0, 0, 1, 1, 1, 1, 1],
[0, 0, 0, 0, 0, 1, 1, 1, 1],
[0, 0, 0, 0, 0, 0, 1, 1, 1],
[0, 0, 0, 0, 0, 0, 0, 1, 1],
[0, 0, 0, 0, 0, 0, 0, 0, 1],
[0, 0, 0, 0, 0, 1, 1, 1, 1],
[0, 0, 1, 0, 0, 1, 1, 1, 1],
[0, 1, 1, 1, 0, 0, 1, 1, 1],
[1, 1, 1, 1, 0, 0, 1, 1, 1],
[1, 1, 1, 1, 1, 0, 0, 1, 1],
[1, 1, 1, 1, 1, 0, 0, 1, 1]
];
for(var my = 0; my < matrix_h; my++)
{
for(var mx = 0; mx < matrix_w; mx++)
{
if(matrix[my][mx] == 0)
{
var target_x = Math.round(this.mouse_x / this.tile_w + mx);
var target_y = Math.round(this.mouse_y / this.tile_h + my) + 1;
//console.log(target_x, target_y);
if(target_x >= 0 && target_x < this.grid_w && target_y >= 0 && target_y < this.grid_h)
{
this.colored[target_x][target_y] = true;
}
}
}
}
if(this.scene)
{
this.scene.Redraw();
}
},
ClearColored: function(){
for(var x = 0; x < this.grid_w; x++)
{
for(var y = 0; y < this.grid_h; y++)
{
this.colored[x][y] = false;
}
}
}
}
},
scenes: {
main: {
width: 960,
height: 288,
fps: 30,
OnLoad: function(event){
this.Add("controller");
},
OnMouseMove: function(event){
}
}
}
});
var canvas = $("#404canvas")[0];
engine.GetScene("main").Attach(canvas);
$("#404canvas").show();
}

1456
public_html/static/engine.js
File diff suppressed because it is too large
View File

4
public_html/static/jquery.js
File diff suppressed because it is too large
View File

42
public_html/static/script.js

@ -0,0 +1,42 @@
/*
* Cryto Team is more free software. It is licensed under the WTFPL, which
* allows you to do pretty much anything with it, without having to
* ask permission. Commercial use is allowed, and no attribution is
* required. We do politely request that you share your modifications
* to benefit other developers, but you are under no enforced
* obligation to do so :)
*
* Please read the accompanying LICENSE document for the full WTFPL
* licensing text.
*/
$(function(){
$('.clickable').click(function(event)
{
if($(this).data('url'))
{
url = $(this).data('url');
if(event.which == 1)
{
if($(this).hasClass('external'))
{
window.open(url);
}
else
{
window.location = url;
}
event.stopPropagation();
return false;
}
else if(event.which == 2)
{
window.open(url);
event.stopPropagation();
return false;
}
}
});
});

316
public_html/static/style.css

@ -1,9 +1,9 @@
@font-face {
font-family: "FontAwesome";
src: url('/static/fontawesome-webfont.eot');
src: url('/static/fontawesome-webfont.eot?#iefix') format('eot'), url('/static/fontawesome-webfont.woff') format('woff'), url('/static/fontawesome-webfont.ttf') format('truetype'), url('/static/fontawesome-webfont.svg#FontAwesome') format('svg');
font-weight: normal;
font-style: normal;
font-family: "FontAwesome";
src: url('/static/fontawesome-webfont.eot');
src: url('/static/fontawesome-webfont.eot?#iefix') format('eot'), url('/static/fontawesome-webfont.woff') format('woff'), url('/static/fontawesome-webfont.ttf') format('truetype'), url('/static/fontawesome-webfont.svg#FontAwesome') format('svg');
font-weight: normal;
font-style: normal;
}
body
@ -17,6 +17,28 @@ body
clear: both;
}
/************************************************
** Clickable rows **
************************************************/
table tr.clickable
{
cursor: pointer;
}
table tr.clickable a
{
/* This gets rid of the link styling for fallback hyperlinks in clickable table rows. */
color: inherit;
text-decoration: none;
}
/************************************************
** Page layout **
************************************************/
.wrapper
{
width: 960px;
@ -46,12 +68,18 @@ body
margin: 0px;
}
/*.header h2:before
.footer
{
font-weight: normal;
content: ";";
margin: 0px 16px;
}*/
border-top: 3px solid black;
margin-top: 12px;
padding-top: 6px;
font-size: 12px;
}
/************************************************
** Page menu **
************************************************/
.menu
{
@ -95,30 +123,27 @@ body
color: white;
}
.main
{
}
.footer
/************************************************
** Sections **
************************************************/
section
{
border-top: 3px solid black;
margin-top: 12px;
padding-top: 6px;
font-size: 12px;
padding: 12px 0px;
}
section
div.section
{
padding: 12px 0px;
margin: 12px 0px;
}
section h3
section h3, div.section h3
{
margin-top: 6px;
}
section p
section p, div.section p
{
font-size: 14px;
}
@ -128,6 +153,11 @@ p.lead
font-weight: bold;
}
/************************************************
** Asides **
************************************************/
aside
{
float: right;
@ -156,58 +186,96 @@ aside section h3
font-size: 19px;
}
section.statistics ul, section.tickets ul
/************************************************
** Generic table styling **
************************************************/
table
{
width: 100%;
border-spacing: 0px;
border-collapse: collapse;
}
table th, table td
{
text-align: left;
padding: 7px 7px;
border-left: 1px solid #252525;
border-right: 1px solid #252525;
}
table th
{
background-color: black;
color: white;
font-size: 12px;
}
table td
{
border: 1px solid #A1A1A1;
}
table th.empty table td.empty
{
margin: 0px;
padding: 0px;
list-style: none;
}
section.statistics
table td
{
/*color: #ECFFBF;*/
font-size: 13px;
}
section.tickets, section.tickets a
/************************************************
** Overview asides **
************************************************/
aside section.statistics ul, section.tickets ul
{
margin: 0px;
padding: 0px;
list-style: none;
}
aside section.tickets, section.tickets a
{
/*color: #FFFBD5;*/
font-size: 12px;
text-decoration: none;
}
section.tickets strong
aside section.tickets strong
{
font-size: 14px;
}
section.tickets ul li
aside section.tickets ul li
{
margin-top: -1px;
margin-bottom: 0px;
/*border-top: 1px solid #FFE8BF;
border-bottom: 1px solid #FFE8BF;*/
border-top: 1px solid #FFFFFF;
border-bottom: 1px solid #FFFFFF;
padding: 6px 0px;
}
section.tickets ul li.more
aside section.tickets ul li.more
{
text-align: right;
border: none;
}
section.tickets ul li.more a
aside section.tickets ul li.more a
{
padding: 3px 6px;
}
section.tickets ul li.more a:hover
aside section.tickets ul li.more a:hover
{
background-color: black;
}
section.download a.download
aside section.download a.download
{
margin-top: 10px;
display: block;
@ -218,7 +286,7 @@ section.download a.download
}
section.download a.download:hover
aside section.download a.download:hover
{
color: white;
background-color: #0C0C0C;
@ -226,13 +294,13 @@ section.download a.download:hover
}
section.download a.download strong
aside section.download a.download strong
{
display: block;
font-size: 18px;
}
section.download a.download b:before
aside section.download a.download b:before
{
display: block;
float: left;
@ -245,12 +313,174 @@ section.download a.download b:before
text-align: center;
}
section.download a.download b.stable:before
aside section.download a.download b.stable:before
{
content: "\f019";
}
section.download a.download b.experimental:before
aside section.download a.download b.experimental:before
{
content: "\f0c3";
}
/************************************************
** Tickets **
************************************************/
section.tickets tr.priority-low
{
color: #2B2B2B;
background-color: #EDEDED;
}
section.tickets tr.priority-low:hover
{
background-color: #E3E3E3;
}
section.tickets tr.priority-normal
{
color: black;
background-color: #E7F7F7;
}
section.tickets tr.priority-normal:hover
{
background-color: #DEEEEE;
}
section.tickets tr.priority-high
{
background-color: #F7D6D6;
}
section.tickets tr.priority-high:hover
{
background-color: #EECECE;
}
section.tickets tr.priority-high td.priority
{
color: red;
font-weight: bold;
}
section.tickets tr.status-closed
{
color: gray;
background-color: #D0D0D0;
}
section.tickets tr.status-closed:hover
{
background-color: #C7C7C7;
}
section.tickets tr.status-closed.priority-high td.priority
{
color: #656565;
}
/************************************************
** Ticket lookup **
************************************************/
.section.ticket-original
{
border: 1px solid #373737;
}
.section.ticket-original h2
{
margin: 0px;
padding: 9px 8px;
background-color: #373737;
color: white;
font-size: 16px;
font-weight: normal;
}
.section.ticket-original .metadata
{
margin: 11px;
font-size: 13px;
}
.section.ticket-original .metadata .currentdata, .section.ticket-original .metadata .originaldata
{
float: left;
width: 50%;
}
.section.ticket-original .metadata .key
{
font-weight: bold;
margin-right: 8px;
}
.section.ticket-original .metadata > div > div
{
margin-top: 4px;
}
.section.ticket-original .body
{
margin: 11px;
padding-left: 4px;
font-size: 15px;
}
.section.ticket-updates > div
{
margin-bottom: 12px;
}
.section.ticket-updates .message
{
border: 1px solid #373737;
padding: 11px;
}
.section.ticket-updates .message .metadata
{
font-size: 15px;
}
.section.ticket-updates .message .metadata .author
{
font-weight: bold;
margin-right: 8px;
}
.section.ticket-updates .message .metadata .date
{
float: right;
color: #585858;
}
.section.ticket-updates .message p
{
margin-bottom: 0px;
}
.section.ticket-updates .event
{
color: white;
background-color: #373737;
padding: 12px;
font-size: 13px;
}
.section.ticket-updates .event .author, .section.ticket-updates .event .value
{
font-weight: bold;
}
.section.ticket-updates .event .date
{
float: right;
color: #DADADA;
}

10
public_html/templates/error/404.tpl

@ -0,0 +1,10 @@
<script src="/static/engine.js"></script>
<script src="/static/404.js"></script>
<div class="section" style="position: relative; height: 288px;">
<canvas id="404canvas" style="z-index: 2; position: absolute; top: 0px; left: 0px;"></canvas>
<div style="z-index: 1; position: absolute; top: 0px; left: 12px;">
<h2>404 Page not found</h2>
The requested page could not be found.
</div>
</div>

13
public_html/templates/home/layout.tpl

@ -0,0 +1,13 @@
<div class="header">
<h1>Team</h1>
<div class="clear"></div>
</div>
<ul class="menu">
<!-- <li class="active"><a href="#">Overview</a></li>
<li><a href="#">Account</a></li>
<li class="clear"></li> -->
</ul>
<div class="main">
{%?contents}
<div class="clear"></div>
</div>

72
public_html/templates/layout.tpl

@ -4,78 +4,12 @@
<title>Cryto Team</title>
<link href='http://fonts.googleapis.com/css?family=Nobile:400,400italic,700,700italic' rel='stylesheet' type='text/css'>
<link rel="stylesheet" href="/static/style.css">
<script src="/static/jquery.js"></script>
<script src="/static/script.js"></script>
</head>
<body>
<div class="wrapper">
<div class="header">
<h1>Team</h1>
<h2>{%?project-name}</h2>
<div class="clear"></div>
</div>
<ul class="menu">
<li class="active"><a href="#">Overview</a></li>
<li><a href="#">Downloads</a></li>
<li><a href="#">Code</a></li>
<li><a href="#">Tickets</a></li>
<li><a href="#">Forum</a></li>
<li><a href="#">Contributors</a></li>
<li><a href="#">Invitations</a></li>
<li class="clear"></li>
</ul>
<div class="main">
<aside>
<section class="download">
<h3>Downloads</h3>
{%if isempty|stable-version == false}
<a href="download/stable" class="download">
<b class="stable"></b>
<strong>Latest stable</strong>
{%?stable-version}
</a>
{%/if}
{%if isempty|experimental-version == false}
<a href="download/experimental" class="download">
<b class="experimental"></b>
<strong>Latest testing</strong>
{%?experimental-version}
</a>
{%/if}
{%if no-downloads == true}
There are no downloads for this project yet.
{%/if}
</section>
<section class="statistics">
<h3>Statistics</h3>
<ul>
<li><strong>{%?line-count}</strong> lines of code</li>
<!-- <li><strong>0</strong> commits</li>
<li><strong>0</strong> contributors</li> -->
<li><strong>{%?ticket-count}</strong> open tickets</li>
</ul>
</section>
<section class="tickets">
<h3>Latest tickets</h3>
<ul>
{%if isempty|tickets == false}
{%foreach ticket in tickets}
<li><strong>{%?ticket[title]}</strong> {%?ticket[date]}</li>
{%/foreach}
{%if more-tickets == true}
<li class="more"><a href="tickets">more...</a></li>
{%/if}
{%else}
No tickets.
{%/if}
</ul>
</section>
</aside>
<section class="intro">
<h3>Introduction</h3>
{%?long-description}
</section>
<div class="clear"></div>
</div>
{%?contents}
<div class="footer">
Cryto Team is a free project management and hosting service for non-profit projects. <a href="/signup">Sign up today!</a>
</div>

51
public_html/templates/project/index.tpl

@ -0,0 +1,51 @@
<aside>
<section class="download">
<h3>Downloads</h3>
{%if isempty|stable-version == false}
<a href="{%?project-url}/download/stable" class="download">
<b class="stable"></b>
<strong>Latest stable</strong>
{%?stable-version}
</a>
{%/if}
{%if isempty|experimental-version == false}
<a href="{%?project-url}/download/experimental" class="download">
<b class="experimental"></b>
<strong>Latest testing</strong>
{%?experimental-version}
</a>
{%/if}
{%if no-downloads == true}
There are no downloads for this project yet.
{%/if}
</section>
<section class="statistics">
<h3>Statistics</h3>
<ul>
<li><strong>{%?line-count}</strong> lines of code</li>
<!-- <li><strong>0</strong> commits</li>
<li><strong>0</strong> contributors</li> -->
<li><strong>{%?ticket-count}</strong> open tickets</li>
</ul>
</section>
<section class="tickets">
<h3>Latest tickets</h3>
<ul>
{%if isempty|tickets == false}
{%foreach ticket in tickets}
<li><strong>{%?ticket[title]}</strong> {%?ticket[date]}</li>
{%/foreach}
{%if more-tickets == true}
<li class="more"><a href="{%?project-url}/tickets">more...</a></li>
{%/if}
{%else}
No tickets.
{%/if}
</ul>
</section>
</aside>
<section class="intro">
<h3>Introduction</h3>
{%?long-description}
</section>

19
public_html/templates/project/layout.tpl

@ -0,0 +1,19 @@
<div class="header">
<h1>Team</h1>
<h2>{%?project-name}</h2>
<div class="clear"></div>
</div>
<ul class="menu">
<li {%if current-page == "overview"}class="active"{%/if}><a href="{%?project-url}">Overview</a></li>
<li {%if current-page == "downloads"}class="active"{%/if}><a href="{%?project-url}/downloads">Downloads</a></li>
<li {%if current-page == "code"}class="active"{%/if}><a href="{%?project-url}/code">Code</a></li>
<li {%if current-page == "tickets"}class="active"{%/if}><a href="{%?project-url}/tickets">Tickets</a></li>
<li {%if current-page == "forum"}class="active"{%/if}><a href="{%?project-url}/forum">Forum</a></li>
<li {%if current-page == "contributors"}class="active"{%/if}><a href="{%?project-url}/contributors">Contributors</a></li>
<li {%if current-page == "invitations"}class="active"{%/if}><a href="{%?project-url}/invitations">Invitations</a></li>
<li class="clear"></li>
</ul>
<div class="main">
{%?contents}
<div class="clear"></div>
</div>

18
public_html/templates/project/tickets/index.tpl

@ -0,0 +1,18 @@
<section class="tickets">
<table>
<tr>
<th class="empty"></th>
<th>Title</th>
<th>Priority</th>
<th>Status</th>
</tr>
{%foreach ticket in tickets}
<tr class="clickable priority-{%?ticket[priority-lowercase]} status-{%