Compare commits

...

20 Commits

Author SHA1 Message Date
Sven Slootweg 6f9e4ccc8d Add salt key to default configuration 10 years ago
Sven Slootweg 8854947866 Display a regular 404 error when a project does not exist 10 years ago
Sven Slootweg 9456a01c34 Tweak ticket display 11 years ago
Sven Slootweg 724dec5a61 Actually get ticket data from the database 11 years ago
Sven Slootweg 21da4e580f Move ticket response date to the right hand side 11 years ago
Sven Slootweg 3f0728b945 Create a fance 404 page :) 11 years ago
Sven Slootweg 08b7a7d825 Basic design for ticket lookup page 11 years ago
Sven Slootweg d6588b6f1a Fix constants, output tickets from database, and implement status/priority names for Ticket objects 11 years ago
Sven Slootweg 853bb50ab6 Fix license notice 11 years ago
Sven Slootweg 30de910e73 Fix license notice, make ticket rows clickable, and get data from variables 11 years ago
Sven Slootweg 5bf96a8d02 Add clickable styles and reorganize stylesheet 11 years ago
Sven Slootweg 73310dbbdc Make minor changes to color scheme 11 years ago
Sven Slootweg 0fe01a0336 Add 'new' ticket status for unreviewed tickets 11 years ago
Sven Slootweg 1bdc620153 Some first attempts at a ticket list color scheme and page layout 11 years ago
Sven Slootweg 3ac9274b1f Return a 404 error when a page does not exist 11 years ago
Sven Slootweg a597290a01 Make routing code a lot cleaner and less repetitive 11 years ago
Sven Slootweg c28cecd570 Whoops, capitalization mistake 11 years ago
Sven Slootweg c2e374964a Fix project-not-found page and project URLs 11 years ago
Sven Slootweg 3dc8c8b08a Add some stuff, remove active config.json from tracked files, update config 11 years ago
Sven Slootweg 48b4b80447 Progress... 11 years ago

1
.gitignore vendored

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

@ -1,6 +1,7 @@
{
"database": {
"driver": "mysql",
"pdo": true,
"hostname": "localhost",
"username": "root",
"password": "",
@ -23,10 +24,15 @@
"interestgroup": "InterestGroup",
"project": "Project",
"repository": "Repository",
"ticket": "Ticket"
"ticket": "Ticket",
"tickettag": "TicketTag",
"ticketmessage": "TicketMessage",
"ticketattachment": "TicketAttachment",
"logentry": "LogEntry"
},
"components": [
"router",
"errorhandler"
]
],
"salt": "abcdef"
}

@ -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");
}

@ -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

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

@ -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";
}
}
}

@ -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";
}
}
}
}

@ -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();

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

@ -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,

@ -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");

@ -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());

@ -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";

@ -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
));

@ -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
));

@ -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");
}

@ -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
)));

@ -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();
}

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

@ -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;
}
}
});
});

@ -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
{
}
/************************************************
** Sections **
************************************************/
.footer
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
{
font-size: 13px;
}
/************************************************
** Overview asides **
************************************************/
aside section.statistics ul, section.tickets ul
{
/*color: #ECFFBF;*/
margin: 0px;
padding: 0px;
list-style: none;
}
section.tickets, section.tickets a
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;
}

@ -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>

@ -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>

@ -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>

@ -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>

@ -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>

@ -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-{%?ticket[status-lowercase]}" data-url="{%?project-url}/ticket/{%?ticket[id]}">
<td class="id">#{%?ticket[id]}</td>
<td class="title"><a href="{%?project-url}/ticket/{%?ticket[id]}">{%?ticket[title]}</a></td>
<td class="priority">{%?ticket[priority]}</td>
<td class="status">{%?ticket[status]}</td>
</tr>
{%/foreach}
</table>
</section>

@ -0,0 +1,58 @@
<div class="section ticket-original">
<h2>{%?title}</h2>
<div class="metadata">
<div class="currentdata">
<div class="priority">
<span class="key">Priority:</span>
<span class="value">{%?priority}</span>
</div>
<div class="status">
<span class="key">Status:</span>
<span class="value">{%?status}</span>
</div>
<div class="owner">
<span class="key">Owner:</span>
<span class="value">{%?owner}</span>
</div>
</div>
<div class="originaldata">
<div class="creator">
<span class="key">Creator:</span>
<span class="value">{%?creator}</span>
</div>
<div class="date">
<span class="key">Date:</span>
<span class="value">{%?date}</span>
</div>
</div>
<div class="clear"></div>
</div>
<div class="body">
{%?body}
</div>
</div>
<div class="section ticket-updates">
{%foreach update in updates}
{%if update[event] == true}
<div class="event">
{%if update[component] == "owner"}
<span class="author">{%?update[user]}</span> changed the owner to <span class="value">{%?update[operation]}</span>.
{%elseif update[component] == "status"}
<span class="author">{%?update[user]}</span> changed the ticket status to <span class="value">{%?update[operation]}</span>.
{%elseif update[component] == "priority"}
<span class="author">{%?update[user]}</span> changed the priority to <span class="value">{%?update[operation]}</span>.
{%/if}
<div class="date">{%?update[date]}</div>
</div>
{%else}
<div class="message">
<div class="metadata">
<span class="author">{%?update[author]}</span>
<span class="date">{%?update[date]}</span>
</div>
<p>{%?update[body]}</p>
</div>
{%/if}
{%/foreach}
</div>
Loading…
Cancel
Save