argument, this creates a tarball of the tag.
+#
+# Examples:
+#
+# ./maketarball
+# ./maketarball v0.0.2
+
+NOWDATE=`date "+%Y-%m-%d"`
+
+if [ -z "$1" ]
+then
+ REVISH=master
+ PREFIX="$NOWDATE-$REVISH"
+else
+ REVISH=$1
+ PREFIX="$REVISH"
+fi
+
+# convert PREFIX to all lowercase.
+# nix the v from tag names.
+PREFIX=`echo "$PREFIX" | tr '[A-Z]' '[a-z]' | sed s/v//`
+
+echo "== REVISH $REVISH"
+echo "== PREFIX $PREFIX"
+
+echo ""
+
+echo "generating archive...."
+git archive \
+ --format=tar \
+ --prefix=mediagoblin-$PREFIX/ \
+ $REVISH > mediagoblin-$PREFIX.tar
+
+if [[ $? -ne 0 ]]
+then
+ echo "git archive command failed. See above text for reason."
+ if [[ -e mediagoblin-$PREFIX.tar ]]
+ then
+ rm mediagoblin-$PREFIX.tar
+ fi
+ exit 1;
+fi
+
+echo "compressing...."
+gzip mediagoblin-$PREFIX.tar
+
+echo "archive at mediagoblin-$PREFIX.tar.gz"
+
+echo "done."
\ No newline at end of file
diff --git a/mediagoblin/app.py b/mediagoblin/app.py
index b27b5761..9454b403 100644
--- a/mediagoblin/app.py
+++ b/mediagoblin/app.py
@@ -21,11 +21,12 @@ import routes
from webob import Request, exc
from mediagoblin import routing, util, storage, staticdirect
-from mediagoblin.config import (
+from mediagoblin.init.config import (
read_mediagoblin_config, generate_validation_report)
from mediagoblin.db.open import setup_connection_and_db_from_config
from mediagoblin.mg_globals import setup_globals
-from mediagoblin.celery_setup import setup_celery_from_config
+from mediagoblin.init.celery import setup_celery_from_config
+from mediagoblin.init import get_jinja_loader
from mediagoblin.workbench import WorkbenchManager
@@ -71,7 +72,7 @@ class MediaGoblinApp(object):
app_config)
# Get the template environment
- self.template_loader = util.get_jinja_loader(
+ self.template_loader = get_jinja_loader(
app_config.get('user_template_path'))
# Set up storage systems
diff --git a/mediagoblin/contrib/960_12_col.css b/mediagoblin/contrib/960_12_col.css
deleted file mode 100644
index 48e86ee8..00000000
--- a/mediagoblin/contrib/960_12_col.css
+++ /dev/null
@@ -1,357 +0,0 @@
-/*
- 960 Grid System ~ Core CSS.
- Learn more ~ http://960.gs/
-
- Licensed under GPL and MIT.
-*/
-
-/*
- Forces backgrounds to span full width,
- even if there is horizontal scrolling.
- Increase this if your layout is wider.
-
- Note: IE6 works fine without this fix.
-*/
-
-body {
- min-width: 960px;
-}
-
-/* `Container
-----------------------------------------------------------------------------------------------------*/
-
-.container_12 {
- margin-left: auto;
- margin-right: auto;
- width: 960px;
-}
-
-/* `Grid >> Global
-----------------------------------------------------------------------------------------------------*/
-
-.grid_1,
-.grid_2,
-.grid_3,
-.grid_4,
-.grid_5,
-.grid_6,
-.grid_7,
-.grid_8,
-.grid_9,
-.grid_10,
-.grid_11,
-.grid_12 {
- display: inline;
- float: left;
- margin-left: 10px;
- margin-right: 10px;
-}
-
-.push_1, .pull_1,
-.push_2, .pull_2,
-.push_3, .pull_3,
-.push_4, .pull_4,
-.push_5, .pull_5,
-.push_6, .pull_6,
-.push_7, .pull_7,
-.push_8, .pull_8,
-.push_9, .pull_9,
-.push_10, .pull_10,
-.push_11, .pull_11 {
- position: relative;
-}
-
-/* `Grid >> Children (Alpha ~ First, Omega ~ Last)
-----------------------------------------------------------------------------------------------------*/
-
-.alpha {
- margin-left: 0;
-}
-
-.omega {
- margin-right: 0;
-}
-
-/* `Grid >> 12 Columns
-----------------------------------------------------------------------------------------------------*/
-
-.container_12 .grid_1 {
- width: 60px;
-}
-
-.container_12 .grid_2 {
- width: 140px;
-}
-
-.container_12 .grid_3 {
- width: 220px;
-}
-
-.container_12 .grid_4 {
- width: 300px;
-}
-
-.container_12 .grid_5 {
- width: 380px;
-}
-
-.container_12 .grid_6 {
- width: 460px;
-}
-
-.container_12 .grid_7 {
- width: 540px;
-}
-
-.container_12 .grid_8 {
- width: 620px;
-}
-
-.container_12 .grid_9 {
- width: 700px;
-}
-
-.container_12 .grid_10 {
- width: 780px;
-}
-
-.container_12 .grid_11 {
- width: 860px;
-}
-
-.container_12 .grid_12 {
- width: 940px;
-}
-
-/* `Prefix Extra Space >> 12 Columns
-----------------------------------------------------------------------------------------------------*/
-
-.container_12 .prefix_1 {
- padding-left: 80px;
-}
-
-.container_12 .prefix_2 {
- padding-left: 160px;
-}
-
-.container_12 .prefix_3 {
- padding-left: 240px;
-}
-
-.container_12 .prefix_4 {
- padding-left: 320px;
-}
-
-.container_12 .prefix_5 {
- padding-left: 400px;
-}
-
-.container_12 .prefix_6 {
- padding-left: 480px;
-}
-
-.container_12 .prefix_7 {
- padding-left: 560px;
-}
-
-.container_12 .prefix_8 {
- padding-left: 640px;
-}
-
-.container_12 .prefix_9 {
- padding-left: 720px;
-}
-
-.container_12 .prefix_10 {
- padding-left: 800px;
-}
-
-.container_12 .prefix_11 {
- padding-left: 880px;
-}
-
-/* `Suffix Extra Space >> 12 Columns
-----------------------------------------------------------------------------------------------------*/
-
-.container_12 .suffix_1 {
- padding-right: 80px;
-}
-
-.container_12 .suffix_2 {
- padding-right: 160px;
-}
-
-.container_12 .suffix_3 {
- padding-right: 240px;
-}
-
-.container_12 .suffix_4 {
- padding-right: 320px;
-}
-
-.container_12 .suffix_5 {
- padding-right: 400px;
-}
-
-.container_12 .suffix_6 {
- padding-right: 480px;
-}
-
-.container_12 .suffix_7 {
- padding-right: 560px;
-}
-
-.container_12 .suffix_8 {
- padding-right: 640px;
-}
-
-.container_12 .suffix_9 {
- padding-right: 720px;
-}
-
-.container_12 .suffix_10 {
- padding-right: 800px;
-}
-
-.container_12 .suffix_11 {
- padding-right: 880px;
-}
-
-/* `Push Space >> 12 Columns
-----------------------------------------------------------------------------------------------------*/
-
-.container_12 .push_1 {
- left: 80px;
-}
-
-.container_12 .push_2 {
- left: 160px;
-}
-
-.container_12 .push_3 {
- left: 240px;
-}
-
-.container_12 .push_4 {
- left: 320px;
-}
-
-.container_12 .push_5 {
- left: 400px;
-}
-
-.container_12 .push_6 {
- left: 480px;
-}
-
-.container_12 .push_7 {
- left: 560px;
-}
-
-.container_12 .push_8 {
- left: 640px;
-}
-
-.container_12 .push_9 {
- left: 720px;
-}
-
-.container_12 .push_10 {
- left: 800px;
-}
-
-.container_12 .push_11 {
- left: 880px;
-}
-
-/* `Pull Space >> 12 Columns
-----------------------------------------------------------------------------------------------------*/
-
-.container_12 .pull_1 {
- left: -80px;
-}
-
-.container_12 .pull_2 {
- left: -160px;
-}
-
-.container_12 .pull_3 {
- left: -240px;
-}
-
-.container_12 .pull_4 {
- left: -320px;
-}
-
-.container_12 .pull_5 {
- left: -400px;
-}
-
-.container_12 .pull_6 {
- left: -480px;
-}
-
-.container_12 .pull_7 {
- left: -560px;
-}
-
-.container_12 .pull_8 {
- left: -640px;
-}
-
-.container_12 .pull_9 {
- left: -720px;
-}
-
-.container_12 .pull_10 {
- left: -800px;
-}
-
-.container_12 .pull_11 {
- left: -880px;
-}
-
-/* `Clear Floated Elements
-----------------------------------------------------------------------------------------------------*/
-
-/* http://sonspring.com/journal/clearing-floats */
-
-.clear {
- clear: both;
- display: block;
- overflow: hidden;
- visibility: hidden;
- width: 0;
- height: 0;
-}
-
-/* http://www.yuiblog.com/blog/2010/09/27/clearfix-reloaded-overflowhidden-demystified */
-
-.clearfix:before,
-.clearfix:after,
-.container_12:before,
-.container_12:after {
- content: '.';
- display: block;
- overflow: hidden;
- visibility: hidden;
- font-size: 0;
- line-height: 0;
- width: 0;
- height: 0;
-}
-
-.clearfix:after,
-.container_12:after {
- clear: both;
-}
-
-/*
- The following zoom:1 rule is specifically for IE6 + IE7.
- Move to separate stylesheet if invalid CSS is a problem.
-*/
-
-.clearfix,
-.container_12 {
- zoom: 1;
-}
\ No newline at end of file
diff --git a/mediagoblin/contrib/960_16_col.css b/mediagoblin/contrib/960_16_col.css
new file mode 100644
index 00000000..faa6d8b2
--- /dev/null
+++ b/mediagoblin/contrib/960_16_col.css
@@ -0,0 +1,447 @@
+/*
+ 960 Grid System ~ Core CSS.
+ Learn more ~ http://960.gs/
+
+ Licensed under GPL and MIT.
+*/
+
+/*
+ Forces backgrounds to span full width,
+ even if there is horizontal scrolling.
+ Increase this if your layout is wider.
+
+ Note: IE6 works fine without this fix.
+*/
+
+body {
+ min-width: 960px;
+}
+
+/* Container
+----------------------------------------------------------------------------------------------------*/
+
+.container_16 {
+ margin-left: auto;
+ margin-right: auto;
+ width: 960px;
+}
+
+/* Grid >> Global
+----------------------------------------------------------------------------------------------------*/
+
+.grid_1,
+.grid_2,
+.grid_3,
+.grid_4,
+.grid_5,
+.grid_6,
+.grid_7,
+.grid_8,
+.grid_9,
+.grid_10,
+.grid_11,
+.grid_12,
+.grid_13,
+.grid_14,
+.grid_15,
+.grid_16 {
+ display: inline;
+ float: left;
+ position: relative;
+ margin-left: 10px;
+ margin-right: 10px;
+}
+
+.push_1, .pull_1,
+.push_2, .pull_2,
+.push_3, .pull_3,
+.push_4, .pull_4,
+.push_5, .pull_5,
+.push_6, .pull_6,
+.push_7, .pull_7,
+.push_8, .pull_8,
+.push_9, .pull_9,
+.push_10, .pull_10,
+.push_11, .pull_11,
+.push_12, .pull_12,
+.push_13, .pull_13,
+.push_14, .pull_14,
+.push_15, .pull_15,
+.push_16, .pull_16 {
+ position: relative;
+}
+
+/* Grid >> Children (Alpha ~ First, Omega ~ Last)
+----------------------------------------------------------------------------------------------------*/
+
+.alpha {
+ margin-left: 0;
+}
+
+.omega {
+ margin-right: 0;
+}
+
+/* Grid >> 16 Columns
+----------------------------------------------------------------------------------------------------*/
+
+.container_16 .grid_1 {
+ width: 40px;
+}
+
+.container_16 .grid_2 {
+ width: 100px;
+}
+
+.container_16 .grid_3 {
+ width: 160px;
+}
+
+.container_16 .grid_4 {
+ width: 220px;
+}
+
+.container_16 .grid_5 {
+ width: 280px;
+}
+
+.container_16 .grid_6 {
+ width: 340px;
+}
+
+.container_16 .grid_7 {
+ width: 400px;
+}
+
+.container_16 .grid_8 {
+ width: 460px;
+}
+
+.container_16 .grid_9 {
+ width: 520px;
+}
+
+.container_16 .grid_10 {
+ width: 580px;
+}
+
+.container_16 .grid_11 {
+ width: 640px;
+}
+
+.container_16 .grid_12 {
+ width: 700px;
+}
+
+.container_16 .grid_13 {
+ width: 760px;
+}
+
+.container_16 .grid_14 {
+ width: 820px;
+}
+
+.container_16 .grid_15 {
+ width: 880px;
+}
+
+.container_16 .grid_16 {
+ width: 940px;
+}
+
+/* Prefix Extra Space >> 16 Columns
+----------------------------------------------------------------------------------------------------*/
+
+.container_16 .prefix_1 {
+ padding-left: 60px;
+}
+
+.container_16 .prefix_2 {
+ padding-left: 120px;
+}
+
+.container_16 .prefix_3 {
+ padding-left: 180px;
+}
+
+.container_16 .prefix_4 {
+ padding-left: 240px;
+}
+
+.container_16 .prefix_5 {
+ padding-left: 300px;
+}
+
+.container_16 .prefix_6 {
+ padding-left: 360px;
+}
+
+.container_16 .prefix_7 {
+ padding-left: 420px;
+}
+
+.container_16 .prefix_8 {
+ padding-left: 480px;
+}
+
+.container_16 .prefix_9 {
+ padding-left: 540px;
+}
+
+.container_16 .prefix_10 {
+ padding-left: 600px;
+}
+
+.container_16 .prefix_11 {
+ padding-left: 660px;
+}
+
+.container_16 .prefix_12 {
+ padding-left: 720px;
+}
+
+.container_16 .prefix_13 {
+ padding-left: 780px;
+}
+
+.container_16 .prefix_14 {
+ padding-left: 840px;
+}
+
+.container_16 .prefix_15 {
+ padding-left: 900px;
+}
+
+/* Suffix Extra Space >> 16 Columns
+----------------------------------------------------------------------------------------------------*/
+
+.container_16 .suffix_1 {
+ padding-right: 60px;
+}
+
+.container_16 .suffix_2 {
+ padding-right: 120px;
+}
+
+.container_16 .suffix_3 {
+ padding-right: 180px;
+}
+
+.container_16 .suffix_4 {
+ padding-right: 240px;
+}
+
+.container_16 .suffix_5 {
+ padding-right: 300px;
+}
+
+.container_16 .suffix_6 {
+ padding-right: 360px;
+}
+
+.container_16 .suffix_7 {
+ padding-right: 420px;
+}
+
+.container_16 .suffix_8 {
+ padding-right: 480px;
+}
+
+.container_16 .suffix_9 {
+ padding-right: 540px;
+}
+
+.container_16 .suffix_10 {
+ padding-right: 600px;
+}
+
+.container_16 .suffix_11 {
+ padding-right: 660px;
+}
+
+.container_16 .suffix_12 {
+ padding-right: 720px;
+}
+
+.container_16 .suffix_13 {
+ padding-right: 780px;
+}
+
+.container_16 .suffix_14 {
+ padding-right: 840px;
+}
+
+.container_16 .suffix_15 {
+ padding-right: 900px;
+}
+
+/* Push Space >> 16 Columns
+----------------------------------------------------------------------------------------------------*/
+
+.container_16 .push_1 {
+ left: 60px;
+}
+
+.container_16 .push_2 {
+ left: 120px;
+}
+
+.container_16 .push_3 {
+ left: 180px;
+}
+
+.container_16 .push_4 {
+ left: 240px;
+}
+
+.container_16 .push_5 {
+ left: 300px;
+}
+
+.container_16 .push_6 {
+ left: 360px;
+}
+
+.container_16 .push_7 {
+ left: 420px;
+}
+
+.container_16 .push_8 {
+ left: 480px;
+}
+
+.container_16 .push_9 {
+ left: 540px;
+}
+
+.container_16 .push_10 {
+ left: 600px;
+}
+
+.container_16 .push_11 {
+ left: 660px;
+}
+
+.container_16 .push_12 {
+ left: 720px;
+}
+
+.container_16 .push_13 {
+ left: 780px;
+}
+
+.container_16 .push_14 {
+ left: 840px;
+}
+
+.container_16 .push_15 {
+ left: 900px;
+}
+
+/* Pull Space >> 16 Columns
+----------------------------------------------------------------------------------------------------*/
+
+.container_16 .pull_1 {
+ left: -60px;
+}
+
+.container_16 .pull_2 {
+ left: -120px;
+}
+
+.container_16 .pull_3 {
+ left: -180px;
+}
+
+.container_16 .pull_4 {
+ left: -240px;
+}
+
+.container_16 .pull_5 {
+ left: -300px;
+}
+
+.container_16 .pull_6 {
+ left: -360px;
+}
+
+.container_16 .pull_7 {
+ left: -420px;
+}
+
+.container_16 .pull_8 {
+ left: -480px;
+}
+
+.container_16 .pull_9 {
+ left: -540px;
+}
+
+.container_16 .pull_10 {
+ left: -600px;
+}
+
+.container_16 .pull_11 {
+ left: -660px;
+}
+
+.container_16 .pull_12 {
+ left: -720px;
+}
+
+.container_16 .pull_13 {
+ left: -780px;
+}
+
+.container_16 .pull_14 {
+ left: -840px;
+}
+
+.container_16 .pull_15 {
+ left: -900px;
+}
+
+/* `Clear Floated Elements
+----------------------------------------------------------------------------------------------------*/
+
+/* http://sonspring.com/journal/clearing-floats */
+
+.clear {
+ clear: both;
+ display: block;
+ overflow: hidden;
+ visibility: hidden;
+ width: 0;
+ height: 0;
+}
+
+/* http://www.yuiblog.com/blog/2010/09/27/clearfix-reloaded-overflowhidden-demystified */
+
+.clearfix:before,
+.clearfix:after,
+.container_16:before,
+.container_16:after {
+ content: '.';
+ display: block;
+ overflow: hidden;
+ visibility: hidden;
+ font-size: 0;
+ line-height: 0;
+ width: 0;
+ height: 0;
+}
+
+.clearfix:after,
+.container_16:after {
+ clear: both;
+}
+
+/*
+ The following zoom:1 rule is specifically for IE6 + IE7.
+ Move to separate stylesheet if invalid CSS is a problem.
+*/
+
+.clearfix,
+.container_16 {
+ zoom: 1;
+}
\ No newline at end of file
diff --git a/mediagoblin/contrib/reset.css b/mediagoblin/contrib/reset.css
new file mode 100644
index 00000000..87b7f368
--- /dev/null
+++ b/mediagoblin/contrib/reset.css
@@ -0,0 +1,202 @@
+/* `XHTML, HTML4, HTML5 Reset
+----------------------------------------------------------------------------------------------------*/
+
+a,
+abbr,
+acronym,
+address,
+applet,
+article,
+aside,
+audio,
+b,
+big,
+blockquote,
+body,
+canvas,
+caption,
+center,
+cite,
+code,
+dd,
+del,
+details,
+dfn,
+dialog,
+div,
+dl,
+dt,
+em,
+embed,
+fieldset,
+figcaption,
+figure,
+font,
+footer,
+form,
+h1,
+h2,
+h3,
+h4,
+h5,
+h6,
+header,
+hgroup,
+hr,
+html,
+i,
+iframe,
+img,
+ins,
+kbd,
+label,
+legend,
+li,
+mark,
+menu,
+meter,
+nav,
+object,
+ol,
+output,
+p,
+pre,
+progress,
+q,
+rp,
+rt,
+ruby,
+s,
+samp,
+section,
+small,
+span,
+strike,
+strong,
+sub,
+summary,
+sup,
+table,
+tbody,
+td,
+tfoot,
+th,
+thead,
+time,
+tr,
+tt,
+u,
+ul,
+var,
+video,
+xmp {
+ border: 0;
+ margin: 0;
+ padding: 0;
+ font-size: 100%;
+}
+
+html,
+body {
+ height: 100%;
+}
+
+article,
+aside,
+details,
+figcaption,
+figure,
+footer,
+header,
+hgroup,
+menu,
+nav,
+section {
+/*
+ Override the default (display: inline) for
+ browsers that do not recognize HTML5 tags.
+
+ IE8 (and lower) requires a shiv:
+ http://ejohn.org/blog/html5-shiv
+*/
+ display: block;
+}
+
+b,
+strong {
+/*
+ Makes browsers agree.
+ IE + Opera = font-weight: bold.
+ Gecko + WebKit = font-weight: bolder.
+*/
+ font-weight: bold;
+}
+
+img {
+ color: transparent;
+ font-size: 0;
+ vertical-align: middle;
+/*
+ For IE.
+ http://css-tricks.com/ie-fix-bicubic-scaling-for-images
+*/
+ -ms-interpolation-mode: bicubic;
+}
+
+li {
+/*
+ For IE6 + IE7.
+*/
+ display: list-item;
+}
+
+table {
+ border-collapse: collapse;
+ border-spacing: 0;
+}
+
+th,
+td,
+caption {
+ font-weight: normal;
+ vertical-align: top;
+ text-align: left;
+}
+
+q {
+ quotes: none;
+}
+
+q:before,
+q:after {
+ content: '';
+ content: none;
+}
+
+sub,
+sup,
+small {
+ font-size: 75%;
+}
+
+sub,
+sup {
+ line-height: 0;
+ position: relative;
+ vertical-align: baseline;
+}
+
+sub {
+ bottom: -0.25em;
+}
+
+sup {
+ top: -0.5em;
+}
+
+svg {
+/*
+ For IE9.
+*/
+ overflow: hidden;
+}
\ No newline at end of file
diff --git a/mediagoblin/contrib/text.css b/mediagoblin/contrib/text.css
new file mode 100644
index 00000000..1a6b302f
--- /dev/null
+++ b/mediagoblin/contrib/text.css
@@ -0,0 +1,86 @@
+/*
+ 960 Grid System ~ Text CSS.
+ Learn more ~ http://960.gs/
+
+ Licensed under GPL and MIT.
+*/
+
+/* `Basic HTML
+----------------------------------------------------------------------------------------------------*/
+
+body {
+ font: 13px/1.5 'Helvetica Neue', Arial, 'Liberation Sans', FreeSans, sans-serif;
+}
+
+pre,
+code {
+ font-family: 'DejaVu Sans Mono', Monaco, Consolas, monospace;
+}
+
+hr {
+ border: 0 #ccc solid;
+ border-top-width: 1px;
+ clear: both;
+ height: 0;
+}
+
+/* `Headings
+----------------------------------------------------------------------------------------------------*/
+
+h1 {
+ font-size: 25px;
+}
+
+h2 {
+ font-size: 23px;
+}
+
+h3 {
+ font-size: 21px;
+}
+
+h4 {
+ font-size: 19px;
+}
+
+h5 {
+ font-size: 17px;
+}
+
+h6 {
+ font-size: 15px;
+}
+
+/* `Spacing
+----------------------------------------------------------------------------------------------------*/
+
+ol {
+ list-style: decimal;
+}
+
+ul {
+ list-style: disc;
+}
+
+li {
+ margin-left: 30px;
+}
+
+p,
+dl,
+hr,
+h1,
+h2,
+h3,
+h4,
+h5,
+h6,
+ol,
+ul,
+pre,
+table,
+address,
+fieldset,
+figure {
+ margin-bottom: 20px;
+}
\ No newline at end of file
diff --git a/mediagoblin/db/__init__.py b/mediagoblin/db/__init__.py
index c129cbf8..776025ca 100644
--- a/mediagoblin/db/__init__.py
+++ b/mediagoblin/db/__init__.py
@@ -13,3 +13,49 @@
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
+
+"""
+Database Abstraction/Wrapper Layer
+==================================
+
+ **NOTE from Chris Webber:** I asked Elrond to explain why he put
+ ASCENDING and DESCENDING in db/util.py when we could just import from
+ pymongo. Read beow for why, but note that nobody is actually doing
+ this and there's no proof that we'll ever support more than
+ MongoDB... it would be a huge amount of work to do so.
+
+ If you really want to prove that possible, jump on IRC and talk to
+ us about making such a branch. In the meanwhile, it doesn't hurt to
+ have things as they are... if it ever makes it hard for us to
+ actually do things, we might revisit or remove this. But for more
+ information, read below.
+
+This submodule is for most of the db specific stuff.
+
+There are two main ideas here:
+
+1. Open up a small possibility to replace mongo by another
+ db. This means, that all direct mongo accesses should
+ happen in the db submodule. While all the rest uses an
+ API defined by this submodule.
+
+ Currently this API happens to be basicly mongo.
+ Which means, that the abstraction/wrapper layer is
+ extremely thin.
+
+2. Give the rest of the app a simple and easy way to get most of
+ their db needs. Which often means some simple import
+ from db.util.
+
+What does that mean?
+
+* Never import mongo directly outside of this submodule.
+
+* Inside this submodule you can do whatever is needed. The
+ API border is exactly at the submodule layer. Nowhere
+ else.
+
+* helper functions can be moved in here. They become part
+ of the db.* API
+
+"""
diff --git a/mediagoblin/db/models.py b/mediagoblin/db/models.py
index bf825a23..8aa35ca9 100644
--- a/mediagoblin/db/models.py
+++ b/mediagoblin/db/models.py
@@ -22,8 +22,7 @@ from mediagoblin import util
from mediagoblin.auth import lib as auth_lib
from mediagoblin import mg_globals
from mediagoblin.db import migrations
-from mediagoblin.db.util import DESCENDING, ObjectId
-from mediagoblin.util import Pagination
+from mediagoblin.db.util import ASCENDING, DESCENDING, ObjectId
###################
# Custom validators
@@ -109,24 +108,13 @@ class MediaEntry(Document):
migration_handler = migrations.MediaEntryMigration
+ def get_comments(self):
+ return self.db.MediaComment.find({
+ 'media_entry': self['_id']}).sort('created', DESCENDING)
+
def main_mediafile(self):
pass
-
- def get_comments(self, page):
- cursor = self.db.MediaComment.find({
- 'media_entry': self['_id']}).sort('created', DESCENDING)
-
- pagination = Pagination(page, cursor)
- comments = pagination()
-
- data = list()
- for comment in comments:
- comment['author'] = self.db.User.find_one({
- '_id': comment['author']})
- data.append(comment)
-
- return (data, pagination)
-
+
def generate_slug(self):
self['slug'] = util.slugify(self['title'])
@@ -154,6 +142,32 @@ class MediaEntry(Document):
'mediagoblin.user_pages.media_home',
user=uploader['username'],
media=unicode(self['_id']))
+
+ def url_to_prev(self, urlgen):
+ """
+ Provide a url to the previous entry from this user, if there is one
+ """
+ cursor = self.db.MediaEntry.find({'_id' : {"$lt": self['_id']},
+ 'uploader': self['uploader']}).sort(
+ '_id', DESCENDING).limit(1)
+
+ if cursor.count():
+ return urlgen('mediagoblin.user_pages.media_home',
+ user=self.uploader()['username'],
+ media=unicode(cursor[0]['_id']))
+
+ def url_to_next(self, urlgen):
+ """
+ Provide a url to the next entry from this user, if there is one
+ """
+ cursor = self.db.MediaEntry.find({'_id' : {"$gt": self['_id']},
+ 'uploader': self['uploader']}).sort(
+ '_id', ASCENDING).limit(1)
+
+ if cursor.count():
+ return urlgen('mediagoblin.user_pages.media_home',
+ user=self.uploader()['username'],
+ media=unicode(cursor[0]['_id']))
def uploader(self):
return self.db.User.find_one({'_id': self['uploader']})
diff --git a/mediagoblin/db/util.py b/mediagoblin/db/util.py
index 46f899f7..70c37945 100644
--- a/mediagoblin/db/util.py
+++ b/mediagoblin/db/util.py
@@ -30,7 +30,7 @@ document relevant to here:
import copy
# Imports that other modules might use
-from pymongo import DESCENDING
+from pymongo import ASCENDING, DESCENDING
from pymongo.errors import InvalidId
from mongokit import ObjectId
diff --git a/mediagoblin/edit/views.py b/mediagoblin/edit/views.py
index a9071495..e064a9c3 100644
--- a/mediagoblin/edit/views.py
+++ b/mediagoblin/edit/views.py
@@ -17,6 +17,7 @@
from webob import exc
+from mediagoblin import messages
from mediagoblin.util import render_to_response, redirect, clean_html
from mediagoblin.edit import forms
from mediagoblin.edit.lib import may_edit_media
@@ -63,6 +64,14 @@ def edit_media(request, media):
return redirect(request, "mediagoblin.user_pages.media_home",
user=media.uploader()['username'], media=media['slug'])
+ if request.user['is_admin'] \
+ and media['uploader'] != request.user['_id'] \
+ and request.method != 'POST':
+ messages.add_message(
+ request, messages.WARNING,
+ "You are editing another user's media. Proceed with caution.")
+
+
return render_to_response(
request,
'mediagoblin/edit/edit.html',
@@ -73,7 +82,18 @@ def edit_media(request, media):
@require_active_login
def edit_profile(request):
- user = request.user
+ # admins may edit any user profile given a username in the querystring
+ edit_username = request.GET.get('username')
+ if request.user['is_admin'] and request.user['username'] != edit_username:
+ user = request.db.User.find_one({'username': edit_username})
+ # No need to warn again if admin just submitted an edited profile
+ if request.method != 'POST':
+ messages.add_message(
+ request, messages.WARNING,
+ "You are editing a user's profile. Proceed with caution.")
+ else:
+ user = request.user
+
form = forms.EditProfileForm(request.POST,
url = user.get('url'),
bio = user.get('bio'))
@@ -83,7 +103,12 @@ def edit_profile(request):
user['bio'] = request.POST['bio']
user.save()
- return redirect(request, "index", user=user['username'])
+ messages.add_message(request,
+ messages.SUCCESS,
+ 'Profile edited!')
+ return redirect(request,
+ "mediagoblin.edit.profile",
+ username=edit_username)
return render_to_response(
request,
diff --git a/mediagoblin/templates/mediagoblin/media_details.html b/mediagoblin/init/__init__.py
similarity index 53%
rename from mediagoblin/templates/mediagoblin/media_details.html
rename to mediagoblin/init/__init__.py
index 0e907616..b8ed2456 100644
--- a/mediagoblin/templates/mediagoblin/media_details.html
+++ b/mediagoblin/init/__init__.py
@@ -1,4 +1,3 @@
-{#
# GNU MediaGoblin -- federated, autonomous media hosting
# Copyright (C) 2011 Free Software Foundation, Inc
#
@@ -14,24 +13,21 @@
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-#}
-{% extends "mediagoblin/base.html" %}
-{% block mediagoblin_content %}
- {# temporarily, an "image gallery" that isn't one really ;) #}
- {% if media %}
-
-
- {% else %}
- Sorry, no such media found.
- {% endif %}
-{% endblock %}
+
+import jinja2
+
+
+def get_jinja_loader(user_template_path=None):
+ """
+ Set up the Jinja template loaders, possibly allowing for user
+ overridden templates.
+
+ (In the future we may have another system for providing theming;
+ for now this is good enough.)
+ """
+ if user_template_path:
+ return jinja2.ChoiceLoader(
+ [jinja2.FileSystemLoader(user_template_path),
+ jinja2.PackageLoader('mediagoblin', 'templates')])
+ else:
+ return jinja2.PackageLoader('mediagoblin', 'templates')
diff --git a/mediagoblin/celery_setup/__init__.py b/mediagoblin/init/celery/__init__.py
similarity index 97%
rename from mediagoblin/celery_setup/__init__.py
rename to mediagoblin/init/celery/__init__.py
index e35dbce2..67c3dfa0 100644
--- a/mediagoblin/celery_setup/__init__.py
+++ b/mediagoblin/init/celery/__init__.py
@@ -20,7 +20,7 @@ import sys
MANDATORY_CELERY_IMPORTS = ['mediagoblin.process_media']
-DEFAULT_SETTINGS_MODULE = 'mediagoblin.celery_setup.dummy_settings_module'
+DEFAULT_SETTINGS_MODULE = 'mediagoblin.init.celery.dummy_settings_module'
def setup_celery_from_config(app_config, global_config,
diff --git a/mediagoblin/celery_setup/dummy_settings_module.py b/mediagoblin/init/celery/dummy_settings_module.py
similarity index 100%
rename from mediagoblin/celery_setup/dummy_settings_module.py
rename to mediagoblin/init/celery/dummy_settings_module.py
diff --git a/mediagoblin/celery_setup/from_celery.py b/mediagoblin/init/celery/from_celery.py
similarity index 97%
rename from mediagoblin/celery_setup/from_celery.py
rename to mediagoblin/init/celery/from_celery.py
index ed0a409e..c053591b 100644
--- a/mediagoblin/celery_setup/from_celery.py
+++ b/mediagoblin/init/celery/from_celery.py
@@ -17,7 +17,7 @@
import os
from mediagoblin import app, mg_globals
-from mediagoblin.celery_setup import setup_celery_from_config
+from mediagoblin.init.celery import setup_celery_from_config
OUR_MODULENAME = __name__
diff --git a/mediagoblin/celery_setup/from_tests.py b/mediagoblin/init/celery/from_tests.py
similarity index 95%
rename from mediagoblin/celery_setup/from_tests.py
rename to mediagoblin/init/celery/from_tests.py
index 779ecd65..b2293e2c 100644
--- a/mediagoblin/celery_setup/from_tests.py
+++ b/mediagoblin/init/celery/from_tests.py
@@ -17,7 +17,7 @@
import os
from mediagoblin.tests.tools import TEST_APP_CONFIG
-from mediagoblin.celery_setup.from_celery import setup_self
+from mediagoblin.init.celery.from_celery import setup_self
OUR_MODULENAME = __name__
diff --git a/mediagoblin/config.py b/mediagoblin/init/config.py
similarity index 100%
rename from mediagoblin/config.py
rename to mediagoblin/init/config.py
diff --git a/mediagoblin/process_media/__init__.py b/mediagoblin/process_media/__init__.py
index 0dce1418..da3e887e 100644
--- a/mediagoblin/process_media/__init__.py
+++ b/mediagoblin/process_media/__init__.py
@@ -21,7 +21,8 @@ from celery.task import task
from mediagoblin import mg_globals as mgg
-THUMB_SIZE = 200, 200
+THUMB_SIZE = 180, 180
+MEDIUM_SIZE = 640, 640
def create_pub_filepath(entry, filename):
@@ -43,20 +44,32 @@ def process_media_initial(media_id):
mgg.queue_store, queued_filepath,
'source')
- queued_file = file(queued_filename, 'r')
+ thumb = Image.open(queued_filename)
+ thumb.thumbnail(THUMB_SIZE, Image.ANTIALIAS)
+ # ensure color mode is compatible with jpg
+ if thumb.mode != "RGB":
+ thumb = thumb.convert("RGB")
- with queued_file:
- thumb = Image.open(queued_file)
- thumb.thumbnail(THUMB_SIZE, Image.ANTIALIAS)
- # ensure color mode is compatible with jpg
- if thumb.mode != "RGB":
- thumb = thumb.convert("RGB")
+ thumb_filepath = create_pub_filepath(entry, 'thumbnail.jpg')
- thumb_filepath = create_pub_filepath(entry, 'thumbnail.jpg')
+ thumb_file = mgg.public_store.get_file(thumb_filepath, 'w')
+ with thumb_file:
+ thumb.save(thumb_file, "JPEG", quality=90)
- thumb_file = mgg.public_store.get_file(thumb_filepath, 'w')
- with thumb_file:
- thumb.save(thumb_file, "JPEG")
+ """
+ Create medium file, used in `media.html`
+ """
+ medium = Image.open(queued_filename)
+ medium.thumbnail(MEDIUM_SIZE, Image.ANTIALIAS)
+
+ if medium.mode != "RGB":
+ medium = medium.convert("RGB")
+
+ medium_filepath = create_pub_filepath(entry, 'medium.jpg')
+
+ medium_file = mgg.public_store.get_file(medium_filepath, 'w')
+ with medium_file:
+ medium.save(medium_file, "JPEG", quality=90)
# we have to re-read because unlike PIL, not everything reads
# things in string representation :)
@@ -73,6 +86,7 @@ def process_media_initial(media_id):
media_files_dict = entry.setdefault('media_files', {})
media_files_dict['thumb'] = thumb_filepath
media_files_dict['main'] = main_filepath
+ media_files_dict['medium'] = medium_filepath
entry['state'] = u'processed'
entry.save()
diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css
index 31573820..53e019f6 100644
--- a/mediagoblin/static/css/base.css
+++ b/mediagoblin/static/css/base.css
@@ -23,10 +23,14 @@ form {
/* text styles */
-h1 {
+h1{
font-family: 'Carter One', arial, serif;
- margin-bottom: 20px;
- margin-top:40px;
+ margin-bottom: 15px;
+ margin-top:15px;
+}
+
+h2{
+ margin-top:20px;
}
p {
@@ -73,47 +77,6 @@ label {
padding-bottom:74px;
}
-ul.mediagoblin_messages {
- list-style:none inside;
- color:#393932;
- margin:2px;
- padding:2px;
-}
-
-ul.mediagoblin_messages li {
- background-color:#d4d4d4;
- border-style:solid;
- border-width:3px;
- border-color:#959595;
- margin:5px;
- padding:8px;
-}
-
-ul.mediagoblin_messages li.message_success {
- background-color: #88d486;
- border-color: #5bba59;
-}
-
-ul.mediagoblin_messages li.message_warning {
- background-color: #d4c686;
- border-color: #baa959;
-}
-
-ul.mediagoblin_messages li.message_error {
- background-color: #d48686;
- border-color: #ba5959;
-}
-
-ul.mediagoblin_messages li.message_info {
- background-color: #86b9d4;
- border-color: #5998ba;
-}
-
-ul.mediagoblin_messages li.message_debug {
- background-color: #aa86d4;
- border-color: #8659ba;
-}
-
a.mediagoblin_logo {
width:34px;
height:25px;
@@ -133,15 +96,6 @@ a.mediagoblin_logo:hover {
/* common website elements */
-.dotted_line {
- width:100%;
- height:0px;
- border-bottom: dotted 1px #5f5f5f;
- position:absolute;
- left:0px;
- margin-top:-20px;
-}
-
.button {
font-family:'Carter One', arial, serif;
height:32px;
@@ -164,6 +118,10 @@ a.mediagoblin_logo:hover {
padding-right:11px;
}
+.pagination{
+text-align:center;
+}
+
/* forms */
.form_box {
@@ -213,30 +171,97 @@ a.mediagoblin_logo:hover {
text-align:right;
}
-/* media pages */
+/* comments */
-.media_image{
- width:640px;
+.comment_author {
+ margin-bottom:40px;
+ padding-top:4px;
}
-.media_sidebar{
- width:280px;
+.comment_content p {
+ margin-bottom:4px;
}
/* media galleries */
-ul.media_thumbnail {
+.media_thumbnail {
padding:0px;
+ width:180px;
+ height:180px;
+ overflow:hidden;
+ float:left;
+ margin:0px 4px 10px 4px;
+ text-align:center;
}
-li.media_thumbnail {
- width:200px;
- height:200px;
- display:-moz-inline-stack;
- display:inline-block;
- vertical-align:top;
- margin:0px 10px 10px 0px;
- text-align:center;
- zoom:1;
-. *display:inline;
+/* icons */
+
+img.media_icon{
+ margin:0 4px;
+ vertical-align:sub;
+}
+
+/* navigation */
+
+.navigation_button{
+ width: 139px;
+ display:block;
+ float:left;
+ text-align: center;
+ background-color: #393939;
+ text-decoration: none;
+ padding: 6px 0pt;
+ font-family: 'Carter One', arial, serif;
+ font-size:2em;
+ margin:0 0 20px
+}
+
+p.navigation_button{
+ color:#272727;
+}
+
+.navigation_left{
+ margin-right:2px;
+}
+
+/* messages */
+
+ul.mediagoblin_messages {
+ list-style:none inside;
+ color:#f7f7f7;
+}
+
+.mediagoblin_messages li {
+ margin:5px 0;
+ padding:8px;
+ text-align:center;
+}
+
+.message_success {
+ background-color: #378566;
+}
+
+.message_warning {
+ background-color: #87453b;
+}
+
+.message_error {
+ background-color: #87453b;
+}
+
+.message_info {
+ background-color: #378566;
+}
+
+.message_debug {
+ background-color: #f7f7f7;
+ color:#272727;
+}
+
+/* profile stuff */
+
+.profile_content {
+ padding: 6px;
+ background-color: #393939;
+ margin-bottom: 10px;
}
diff --git a/mediagoblin/static/css/contrib/960_12_col.css b/mediagoblin/static/css/contrib/960_12_col.css
deleted file mode 120000
index 15c360e4..00000000
--- a/mediagoblin/static/css/contrib/960_12_col.css
+++ /dev/null
@@ -1 +0,0 @@
-../../../contrib/960_12_col.css
\ No newline at end of file
diff --git a/mediagoblin/static/css/contrib/960_16_col.css b/mediagoblin/static/css/contrib/960_16_col.css
new file mode 120000
index 00000000..bc1a430c
--- /dev/null
+++ b/mediagoblin/static/css/contrib/960_16_col.css
@@ -0,0 +1 @@
+../../../contrib/960_16_col.css
\ No newline at end of file
diff --git a/mediagoblin/static/css/contrib/reset.css b/mediagoblin/static/css/contrib/reset.css
new file mode 120000
index 00000000..87ae5592
--- /dev/null
+++ b/mediagoblin/static/css/contrib/reset.css
@@ -0,0 +1 @@
+../../../contrib/reset.css
\ No newline at end of file
diff --git a/mediagoblin/static/css/contrib/text.css b/mediagoblin/static/css/contrib/text.css
new file mode 120000
index 00000000..d75ce48b
--- /dev/null
+++ b/mediagoblin/static/css/contrib/text.css
@@ -0,0 +1 @@
+../../../contrib/text.css
\ No newline at end of file
diff --git a/mediagoblin/static/images/icon_delete.png b/mediagoblin/static/images/icon_delete.png
new file mode 100644
index 00000000..9d76a5db
Binary files /dev/null and b/mediagoblin/static/images/icon_delete.png differ
diff --git a/mediagoblin/static/images/icon_edit.png b/mediagoblin/static/images/icon_edit.png
new file mode 100644
index 00000000..480c73ad
Binary files /dev/null and b/mediagoblin/static/images/icon_edit.png differ
diff --git a/mediagoblin/static/images/icon_feed.png b/mediagoblin/static/images/icon_feed.png
new file mode 100644
index 00000000..11e5b1e7
Binary files /dev/null and b/mediagoblin/static/images/icon_feed.png differ
diff --git a/mediagoblin/submit/views.py b/mediagoblin/submit/views.py
index 6139614e..4c7476b0 100644
--- a/mediagoblin/submit/views.py
+++ b/mediagoblin/submit/views.py
@@ -24,6 +24,7 @@ from mediagoblin.util import (
from mediagoblin.decorators import require_active_login
from mediagoblin.submit import forms as submit_forms, security
from mediagoblin.process_media import process_media_initial
+from mediagoblin.messages import add_message, SUCCESS
@require_active_login
@@ -85,7 +86,10 @@ def submit_start(request):
# queue it for processing
process_media_initial.delay(unicode(entry['_id']))
- return redirect(request, "mediagoblin.submit.success")
+ add_message(request, SUCCESS, 'Woohoo! Submitted!')
+
+ return redirect(request, "mediagoblin.user_pages.user_home",
+ user = request.user['username'])
return render_to_response(
request,
diff --git a/mediagoblin/templates/mediagoblin/auth/login.html b/mediagoblin/templates/mediagoblin/auth/login.html
index f6ee7166..2303ce5c 100644
--- a/mediagoblin/templates/mediagoblin/auth/login.html
+++ b/mediagoblin/templates/mediagoblin/auth/login.html
@@ -20,10 +20,9 @@
{% import "/mediagoblin/utils/wtforms.html" as wtforms_util %}
{% block mediagoblin_content %}
-