Initial pass at S3 version

This commit is contained in:
Jay McCarthy 2013-10-07 14:10:32 -06:00
parent 0371ade45e
commit 4cb98ac8df
8 changed files with 298 additions and 72 deletions

View File

@ -1 +1,5 @@
/root
/static/pkgs
/static/pkg
/static/pkgs-all
*json

View File

@ -0,0 +1,31 @@
#lang racket/base
(require racket/file
racket/runtime-path
pkg/util
racket/string
web-server/http/id-cookie)
(define-runtime-path src ".")
(define-runtime-path root "root")
(make-directory* root)
(define secret-key
(make-secret-salt/file
(build-path root "secret.key")))
(define users-path (build-path root "users"))
(make-directory* users-path)
(define users.new-path (build-path root "users.new"))
(make-directory* users.new-path)
(github-client_id (file->string (build-path root "client_id")))
(github-client_secret (file->string (build-path root "client_secret")))
(define pkgs-path (build-path root "pkgs"))
(make-directory* pkgs-path)
(define static-path (build-path src "static"))
(define (author->list as)
(string-split as))
(provide (all-defined-out))

View File

@ -2,6 +2,7 @@
(module+ test
(require rackunit))
(require web-server/http
"common.rkt"
web-server/servlet-env
racket/file
xml
@ -38,24 +39,6 @@
(define (salty str)
(sha1 (open-input-string str)))
(define-runtime-path src ".")
(define-runtime-path root "root")
(make-directory* root)
(define secret-key
(make-secret-salt/file
(build-path root "secret.key")))
(define users-path (build-path root "users"))
(make-directory* users-path)
(define users.new-path (build-path root "users.new"))
(make-directory* users.new-path)
(github-client_id (file->string (build-path root "client_id")))
(github-client_secret (file->string (build-path root "client_secret")))
(define pkgs-path (build-path root "pkgs"))
(make-directory* pkgs-path)
(define id-cookie-name "pnrid")
;; XXX Add a caching system
@ -159,9 +142,6 @@
new-v]))
#f)))
(define (author->list as)
(string-split as))
(define (page/rss req)
(define ps
(sort (map package-info (package-list))
@ -1132,7 +1112,7 @@
#:ssl-cert (build-path root "server-cert.pem")
#:ssl-key (build-path root "private-key.pem")
#:extra-files-paths
(list (build-path src "static"))
(list static-path)
#:servlet-regexp #rx""
#:port port))

View File

@ -0,0 +1,75 @@
#lang racket/base
(require web-server/http
racket/file
racket/match
json
net/url
racket/list
racket/path
racket/promise
meta/pkg-index/basic/main)
(define convert-to-json
(match-lambda
[(? list? l)
(map convert-to-json l)]
[(? string? s)
s]
[(? hash? ht)
(for/hash ([(k v) (in-hash ht)])
(values (convert-to-json-key k)
(convert-to-json v)))]
[(? number? n)
n]
[#f
#f]
[(? symbol? s)
(symbol->string s)]
[(? keyword? s)
(hasheq 'kw (keyword->string s))]
[x
(error 'convert-to-json "~e" x)]))
(define convert-to-json-key
(match-lambda
[(? string? s)
(string->symbol s)]
[(? symbol? s)
s]
[x
(error 'convert-to-json-key "~e" x)]))
(module+ main
(require "common.rkt")
(define pkg-list
(map path->string (directory-list pkgs-path)))
(define dispatch
(pkg-index/basic
(λ () pkg-list)
(λ (pkg-name)
(define ht (file->value (build-path pkgs-path pkg-name)))
(hash-set* ht
'name pkg-name
'tags (hash-ref ht 'tags empty)
'authors (author->list (hash-ref ht 'author ""))))))
(define (url->request u)
(make-request #"GET" (string->url u) empty
(delay empty) #f "1.2.3.4" 80 "4.3.2.1"))
(define (cache url file)
(define p (build-path static-path file))
(make-directory* (path-only p))
(with-output-to-file p
#:exists 'replace
(λ () ((response-output (dispatch (url->request url))) (current-output-port))))
(with-output-to-file (path-add-suffix p #".json")
#:exists 'replace
(λ () (write-json (convert-to-json (file->value p)))))
(void))
(cache "/pkgs" "pkgs")
(cache "/pkgs-all" "pkgs-all")
(for ([p (in-list pkg-list)])
(cache (format "/pkg/~a" p) (format "pkg/~a" p))))

View File

@ -0,0 +1,39 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html>
<head>
<title>Packages &gt; Search &gt; !main-distribution &gt; !main-tests</title>
<script src="/sorttable.js"></script>
<script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
<script src="/index.js"></script>
<link rel="stylesheet" type="text/css" href="/style.css">
</head>
<body>
<div class="breadcrumb">
<span><a href="/">Packages</a></span> &gt;
<span>Search</span>
<span id="logout">jay.mccarthy@gmail.com | <a href="/curate">curate</a> | <a href="/rss">rss</a> | <a href="/account/login">re-login</a> | <a href="/account/logout">logout</a></span>
</div>
<div id="menu"><form action="/query/search/!main-distribution/!main-tests">
<span class="menu_option"><input name="input_0" type="text"><input type="submit" value="Search"></span><span class="menu_option"><a href="/manage">Manage
Your Packages</a></span>
</form></div>
<p id="search_menu"></p>
<table class="packages sortable">
<thead><tr>
<th>Package</th>
<th>Authors</th>
<th>Description</th>
<th>Tags</th>
</tr></thead>
<tbody id="packages_table">
</tbody>
<tfoot></tfoot>
</table>
<div id="footer">
Powered by <a href="http://racket-lang.org">Racket</a> and a
mess of ugly JS. Written
by <a href="http://faculty.cs.byu.edu/~jay">Jay McCarthy</a>.
</div>
</body>
</html>

View File

@ -0,0 +1,116 @@
// xxx curate
// xxx rss
// xxx re-login
// xxx logout
// xxx what user am i
// xxx manage packages
$( document ).ready(function() {
var search_terms = [ "!main-tests", "!main-distribution" ];
function addfilterlink ( text, term ) {
return [$('<a>', { text: text,
href: "javascript:void(0)",
click: function () {
search_terms.push(term);
evaluate_search();
} } ),
" "
];
};
function removefilterlink ( text, term ) {
return [$('<a>', { text: text,
href: "javascript:void(0)",
click: function () {
search_terms = $.grep( search_terms, function (v) { return v != term } );
evaluate_search();
} } ),
" "
];
};
$.getJSON( "/pkgs-all.json", function( resp ) {
var names = [];
$.each(resp, function(key, value) { names.push(key) });
var snames = names.sort(function(a,b) {
return ((a < b) ? -1 : ((a > b) ? 1 : 0));
})
var now = new Date().getTime() / 1000;
$.each( snames,
function (name_i) {
var name = snames[name_i];
var value = resp[name];
$('<tr>',
{ class: ((now - (60*60*24*2)) < value['last-updated'] ? "recent" : "old") }).
data( "obj", value).append(
$('<td>').html( $('<a>', { text: value['name'],
href: "javascript:void(0)",
click: function () {
// XXX open up a subwindow
console.log(value);
} } ) ),
$('<td>').append( $.map( value['authors'], function ( author, i ) {
return addfilterlink ( author, "author:" + author );
} ) ),
$('<td>').text( value['description'] ),
$('<td>').append( $.map( value['tags'], function ( tag, i ) {
return addfilterlink ( tag, tag );
} ) )).appendTo('#packages_table');
});
evaluate_search();
});
function evaluate_search_term( value, term ) {
if ( term == ":error:") {
return value['checksum-error'];
} else if ( term == ":no-tag:") {
return value['tags'].length == 0;
} else if ( term.substring(0, 5) == "ring:") {
return value['ring'] == term.substring(5);
} else if ( term.substring(0, 7) == "author:") {
return ($.inArray( term.substring(7), value['authors'] ) != -1);
} else if ( term.charAt(0) == "!" ) {
return ! evaluate_search_term( value, term.substring(1) );
} else if ( $.inArray( term, value['tags']) != -1 ) {
return true;
} else {
return false;
}
}
function evaluate_search () {
$.each( $('#packages_table tr'), function (key, dom) {
var value = $(dom).data("obj");
var show = true;
for (termi in search_terms) {
var term = search_terms[termi];
if ( ! evaluate_search_term( value, term ) ) {
show = false;
}
}
if ( show ) {
$(dom).show();
} else {
$(dom).hide();
}
});
// xxx handle search button
// xxx update menu available
$("#search_menu").html("").append( $.map( search_terms, function ( term, i ) {
return removefilterlink ( term, term );
} ) );
$("#packages_table tr:visible:even").removeClass("even");
$("#packages_table tr:visible:odd").addClass("even");
};
});

View File

@ -1,24 +1,3 @@
function TocviewToggle(glyphid, id) {
var glyph = document.getElementById(glyphid);
var s = document.getElementById(id).style;
var expand = s.display == "none";
s.display = expand ? "block" : "none";
glyph.innerHTML = expand ? "&#9660;" : "&#9658;";
}
function ToggleOn(id) {
var s = document.getElementById(id).style;
var li = document.getElementById("li" + id);
s.display = "block";
li.setAttribute("class", "tab-selected");
}
function ToggleOff(id) {
var s = document.getElementById(id).style;
var li = document.getElementById("li" + id);
s.display = "none";
li.setAttribute("class", "");
}
/*
SortTable
version 2
@ -110,7 +89,7 @@ sorttable = {
// make it clickable to sort
headrow[i].sorttable_columnindex = i;
headrow[i].sorttable_tbody = table.tBodies[0];
dean_addEvent(headrow[i],"click", function(e) {
dean_addEvent(headrow[i],"click", sorttable.innerSortFunction = function(e) {
if (this.className.search(/\bsorttable_sorted\b/) != -1) {
// if we're already sorted by this column, just
@ -225,6 +204,8 @@ sorttable = {
// for example, you can override the cell text with a customkey attribute.
// it also gets .value for <input> fields.
if (!node) return "";
hasInputs = (typeof node.getElementsByTagName == 'function') &&
node.getElementsByTagName('input').length;

View File

@ -51,7 +51,7 @@ table.packages thead tr {
background: #FFCC66;
}
table.packages tbody tr:nth-child(2n) {
table.packages tbody tr.even {
background: #F5F5DC;
}