Merge branch 'master' into derek-moore-bug405_email_notifications_for_comments
Conflicts: mediagoblin/db/mongo/migrations.py
This commit is contained in:
commit
94e6052375
1
.gitignore
vendored
1
.gitignore
vendored
@ -9,6 +9,7 @@
|
|||||||
/lib/
|
/lib/
|
||||||
/include/
|
/include/
|
||||||
/parts/
|
/parts/
|
||||||
|
/share/
|
||||||
/mediagoblin.egg-info
|
/mediagoblin.egg-info
|
||||||
/docs/_build/
|
/docs/_build/
|
||||||
/docs/build
|
/docs/build
|
||||||
|
23
extlib/video-js/demo.html
Normal file
23
extlib/video-js/demo.html
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Video.js | HTML5 Video Player</title>
|
||||||
|
|
||||||
|
<link href="http://vjs.zencdn.net/c/video-js.css" rel="stylesheet" type="text/css">
|
||||||
|
|
||||||
|
<!-- video.js must be in the <head> for older IEs to work. -->
|
||||||
|
<script src="http://vjs.zencdn.net/c/video.js"></script>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<video id="example_video_1" class="video-js vjs-default-skin" controls preload="none" width="640" height="264"
|
||||||
|
poster="http://video-js.zencoder.com/oceans-clip.png"
|
||||||
|
data-setup="{}">
|
||||||
|
<source src="http://video-js.zencoder.com/oceans-clip.mp4" type='video/mp4' />
|
||||||
|
<source src="http://video-js.zencoder.com/oceans-clip.webm" type='video/webm' />
|
||||||
|
<source src="http://video-js.zencoder.com/oceans-clip.ogv" type='video/ogg' />
|
||||||
|
</video>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
427
extlib/video-js/video-js.css
Normal file
427
extlib/video-js/video-js.css
Normal file
@ -0,0 +1,427 @@
|
|||||||
|
/*
|
||||||
|
VideoJS Default Styles (http://videojs.com)
|
||||||
|
Version 3.1.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
REQUIRED STYLES (be careful overriding)
|
||||||
|
================================================================================ */
|
||||||
|
/* When loading the player, the video tag is replaced with a DIV,
|
||||||
|
that will hold the video tag or object tag for other playback methods.
|
||||||
|
The div contains the video playback element (Flash or HTML5) and controls, and sets the width and height of the video.
|
||||||
|
|
||||||
|
** If you want to add some kind of border/padding (e.g. a frame), or special positioning, use another containing element.
|
||||||
|
Otherwise you risk messing up control positioning and full window mode. **
|
||||||
|
*/
|
||||||
|
.video-js {
|
||||||
|
background-color: #000; position: relative; padding: 0;
|
||||||
|
|
||||||
|
/* Start with 10px for base font size so other dimensions can be em based and easily calculable. */
|
||||||
|
font-size: 10px;
|
||||||
|
|
||||||
|
/* Allow poster to be vertially aligned. */
|
||||||
|
vertical-align: middle;
|
||||||
|
/* display: table-cell; */ /*This works in Safari but not Firefox.*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Playback technology elements expand to the width/height of the containing div. <video> or <object> */
|
||||||
|
.video-js .vjs-tech { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
|
||||||
|
|
||||||
|
/* Fix for Firefox 9 fullscreen (only if it is enabled). Not needed when checking fullScreenEnabled. */
|
||||||
|
.video-js:-moz-full-screen { position: absolute; }
|
||||||
|
|
||||||
|
/* Fullscreen Styles */
|
||||||
|
body.vjs-full-window {
|
||||||
|
padding: 0; margin: 0;
|
||||||
|
height: 100%; overflow-y: auto; /* Fix for IE6 full-window. http://www.cssplay.co.uk/layouts/fixed.html */
|
||||||
|
}
|
||||||
|
.video-js.vjs-fullscreen {
|
||||||
|
position: fixed; overflow: hidden; z-index: 1000; left: 0; top: 0; bottom: 0; right: 0; width: 100% !important; height: 100% !important;
|
||||||
|
_position: absolute; /* IE6 Full-window (underscore hack) */
|
||||||
|
}
|
||||||
|
.video-js:-webkit-full-screen {
|
||||||
|
width: 100% !important; height: 100% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Poster Styles */
|
||||||
|
.vjs-poster {
|
||||||
|
margin: 0 auto; padding: 0; cursor: pointer;
|
||||||
|
|
||||||
|
/* Scale with the size of the player div. Works when poster is vertically shorter, but stretches when it's less wide. */
|
||||||
|
position: relative; width: 100%; max-height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Subtiles Styles */
|
||||||
|
.video-js .vjs-subtitles { color: #fff; font-size: 20px; text-align: center; position: absolute; bottom: 40px; left: 0; right: 0; }
|
||||||
|
|
||||||
|
/* Fading sytles, used to fade control bar. */
|
||||||
|
.vjs-fade-in {
|
||||||
|
visibility: visible !important; /* Needed to make sure things hide in older browsers too. */
|
||||||
|
opacity: 1 !important;
|
||||||
|
|
||||||
|
-webkit-transition: visibility 0s linear 0s, opacity 0.3s linear;
|
||||||
|
-moz-transition: visibility 0s linear 0s, opacity 0.3s linear;
|
||||||
|
-ms-transition: visibility 0s linear 0s, opacity 0.3s linear;
|
||||||
|
-o-transition: visibility 0s linear 0s, opacity 0.3s linear;
|
||||||
|
transition: visibility 0s linear 0s, opacity 0.3s linear;
|
||||||
|
}
|
||||||
|
.vjs-fade-out {
|
||||||
|
visibility: hidden !important;
|
||||||
|
opacity: 0 !important;
|
||||||
|
|
||||||
|
-webkit-transition: visibility 0s linear 1.5s,opacity 1.5s linear;
|
||||||
|
-moz-transition: visibility 0s linear 1.5s,opacity 1.5s linear;
|
||||||
|
-ms-transition: visibility 0s linear 1.5s,opacity 1.5s linear;
|
||||||
|
-o-transition: visibility 0s linear 1.5s,opacity 1.5s linear;
|
||||||
|
transition: visibility 0s linear 1.5s,opacity 1.5s linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* DEFAULT SKIN (override in another file to create new skins)
|
||||||
|
================================================================================
|
||||||
|
Instead of editing this file, I recommend creating your own skin CSS file to be included after this file,
|
||||||
|
so you can upgrade to newer versions easier. You can remove all these styles by removing the 'vjs-default-skin' class from the tag. */
|
||||||
|
|
||||||
|
/* The default control bar. Created by bar.js */
|
||||||
|
.vjs-default-skin .vjs-controls {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0; /* Distance from the bottom of the box/video. Keep 0. Use height to add more bottom margin. */
|
||||||
|
left: 0; right: 0; /* 100% width of div */
|
||||||
|
margin: 0; padding: 0; /* Controls are absolutely position, so no padding necessary */
|
||||||
|
height: 2.6em; /* Including any margin you want above or below control items */
|
||||||
|
color: #fff; border-top: 1px solid #404040;
|
||||||
|
|
||||||
|
/* CSS Gradient */
|
||||||
|
/* Can use the Ultimate CSS Gradient Generator: http://www.colorzilla.com/gradient-editor/ */
|
||||||
|
background: #242424; /* Old browsers */
|
||||||
|
background: -moz-linear-gradient(top, #242424 50%, #1f1f1f 50%, #171717 100%); /* FF3.6+ */
|
||||||
|
background: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(50%,#242424), color-stop(50%,#1f1f1f), color-stop(100%,#171717)); /* Chrome,Safari4+ */
|
||||||
|
background: -webkit-linear-gradient(top, #242424 50%,#1f1f1f 50%,#171717 100%); /* Chrome10+,Safari5.1+ */
|
||||||
|
background: -o-linear-gradient(top, #242424 50%,#1f1f1f 50%,#171717 100%); /* Opera11.10+ */
|
||||||
|
background: -ms-linear-gradient(top, #242424 50%,#1f1f1f 50%,#171717 100%); /* IE10+ */
|
||||||
|
/* Filter was causing a lot of weird issues in IE. Elements would stop showing up, or other styles would break. */
|
||||||
|
/*filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#242424', endColorstr='#171717',GradientType=0 );*/ /* IE6-9 */
|
||||||
|
background: linear-gradient(top, #242424 50%,#1f1f1f 50%,#171717 100%); /* W3C */
|
||||||
|
|
||||||
|
/* Start hidden and with 0 opacity. Opacity is used to fade in modern browsers. */
|
||||||
|
/* Can't use display block to hide initially because widths of slider handles aren't calculated and avaialbe for positioning correctly. */
|
||||||
|
visibility: hidden;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* General styles for individual controls. */
|
||||||
|
.vjs-default-skin .vjs-control {
|
||||||
|
position: relative; float: left;
|
||||||
|
text-align: center; margin: 0; padding: 0;
|
||||||
|
height: 2.6em; width: 2.6em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vjs-default-skin .vjs-control:focus {
|
||||||
|
outline: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hide control text visually, but have it available for screenreaders: h5bp.com/v */
|
||||||
|
.vjs-default-skin .vjs-control-text { border: 0; clip: rect(0 0 0 0); height: 1px; margin: -1px; overflow: hidden; padding: 0; position: absolute; width: 1px; }
|
||||||
|
|
||||||
|
|
||||||
|
/* Play/Pause
|
||||||
|
-------------------------------------------------------------------------------- */
|
||||||
|
.vjs-default-skin .vjs-play-control { width: 5em; cursor: pointer !important; }
|
||||||
|
/* Play Icon */
|
||||||
|
.vjs-default-skin.vjs-paused .vjs-play-control div { width: 15px; height: 17px; background: url('video-js.png'); margin: 0.5em auto 0; }
|
||||||
|
.vjs-default-skin.vjs-playing .vjs-play-control div { width: 15px; height: 17px; background: url('video-js.png') -25px 0; margin: 0.5em auto 0; }
|
||||||
|
|
||||||
|
/* Rewind
|
||||||
|
-------------------------------------------------------------------------------- */
|
||||||
|
.vjs-default-skin .vjs-rewind-control { width: 5em; cursor: pointer !important; }
|
||||||
|
.vjs-default-skin .vjs-rewind-control div { width: 19px; height: 16px; background: url('video-js.png'); margin: 0.5em auto 0; }
|
||||||
|
|
||||||
|
/* Volume/Mute
|
||||||
|
-------------------------------------------------------------------------------- */
|
||||||
|
.vjs-default-skin .vjs-mute-control { width: 3.8em; cursor: pointer !important; float: right; }
|
||||||
|
.vjs-default-skin .vjs-mute-control div { width: 22px; height: 16px; background: url('video-js.png') -75px -25px; margin: 0.5em auto 0; }
|
||||||
|
.vjs-default-skin .vjs-mute-control.vjs-vol-0 div { background: url('video-js.png') 0 -25px; }
|
||||||
|
.vjs-default-skin .vjs-mute-control.vjs-vol-1 div { background: url('video-js.png') -25px -25px; }
|
||||||
|
.vjs-default-skin .vjs-mute-control.vjs-vol-2 div { background: url('video-js.png') -50px -25px; }
|
||||||
|
|
||||||
|
|
||||||
|
.vjs-default-skin .vjs-volume-control { width: 5em; float: right; }
|
||||||
|
.vjs-default-skin .vjs-volume-bar {
|
||||||
|
position: relative; width: 5em; height: 0.6em; margin: 1em auto 0; cursor: pointer !important;
|
||||||
|
|
||||||
|
-moz-border-radius: 0.3em; -webkit-border-radius: 0.3em; border-radius: 0.3em;
|
||||||
|
|
||||||
|
background: #666;
|
||||||
|
background: -moz-linear-gradient(top, #333, #666);
|
||||||
|
background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#333), to(#666));
|
||||||
|
background: -webkit-linear-gradient(top, #333, #666);
|
||||||
|
background: -o-linear-gradient(top, #333, #666);
|
||||||
|
background: -ms-linear-gradient(top, #333, #666);
|
||||||
|
background: linear-gradient(top, #333, #666);
|
||||||
|
}
|
||||||
|
.vjs-default-skin .vjs-volume-level {
|
||||||
|
position: absolute; top: 0; left: 0; height: 0.6em;
|
||||||
|
|
||||||
|
-moz-border-radius: 0.3em; -webkit-border-radius: 0.3em; border-radius: 0.3em;
|
||||||
|
|
||||||
|
background: #fff;
|
||||||
|
background: -moz-linear-gradient(top, #fff, #ccc);
|
||||||
|
background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#fff), to(#ccc));
|
||||||
|
background: -webkit-linear-gradient(top, #fff, #ccc);
|
||||||
|
background: -o-linear-gradient(top, #fff, #ccc);
|
||||||
|
background: -ms-linear-gradient(top, #fff, #ccc);
|
||||||
|
background: linear-gradient(top, #fff, #ccc);
|
||||||
|
}
|
||||||
|
.vjs-default-skin .vjs-volume-handle {
|
||||||
|
position: absolute; top: -0.2em; width: 0.8em; height: 0.8em; background: #ccc; left: 0;
|
||||||
|
border: 1px solid #fff;
|
||||||
|
-moz-border-radius: 0.6em; -webkit-border-radius: 0.6em; border-radius: 0.6em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Progress
|
||||||
|
-------------------------------------------------------------------------------- */
|
||||||
|
.vjs-default-skin div.vjs-progress-control {
|
||||||
|
position: absolute;
|
||||||
|
left: 4.8em; right: 4.8em; /* Leave room for time displays. */
|
||||||
|
height: 1.0em; width: auto;
|
||||||
|
top: -1.3em; /* Set above the rest of the controls. And leave room for 2px of borders (progress bottom and controls top). */
|
||||||
|
border-bottom: 1px solid #1F1F1F;
|
||||||
|
border-top: 1px solid #222;
|
||||||
|
|
||||||
|
/* CSS Gradient */
|
||||||
|
background: #333;
|
||||||
|
background: -moz-linear-gradient(top, #222, #333);
|
||||||
|
background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#222), to(#333));
|
||||||
|
background: -webkit-linear-gradient(top, #222, #333);
|
||||||
|
background: -o-linear-gradient(top, #333, #222);
|
||||||
|
background: -ms-linear-gradient(top, #333, #222);
|
||||||
|
background: linear-gradient(top, #333, #222);
|
||||||
|
|
||||||
|
|
||||||
|
/* 1px top shadow */
|
||||||
|
/* -webkit-box-shadow: 0px -1px 0px 0px rgba(0, 0, 0, 0.15); -moz-box-shadow: 0px -1px 0px 0px rgba(0, 0, 0, 0.15); box-shadow: 0px -1px 0px 0px rgba(0, 0, 0, 0.15);*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Box containing play and load progresses. Also acts as seek scrubber. */
|
||||||
|
.vjs-default-skin .vjs-progress-holder {
|
||||||
|
position: relative; cursor: pointer !important; /*overflow: hidden;*/
|
||||||
|
padding: 0; margin: 0; /* Placement within the progress control item */
|
||||||
|
height: 1.0em;
|
||||||
|
-moz-border-radius: 0.6em; -webkit-border-radius: 0.6em; border-radius: 0.6em;
|
||||||
|
|
||||||
|
/* CSS Gradient */
|
||||||
|
background: #111;
|
||||||
|
background: -moz-linear-gradient(top, #111, #262626);
|
||||||
|
background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#111), to(#262626));
|
||||||
|
background: -webkit-linear-gradient(top, #111, #262626);
|
||||||
|
background: -o-linear-gradient(top, #111, #262626);
|
||||||
|
background: -ms-linear-gradient(top, #111, #262626);
|
||||||
|
background: linear-gradient(top, #111, #262626);
|
||||||
|
}
|
||||||
|
.vjs-default-skin .vjs-progress-holder .vjs-play-progress,
|
||||||
|
.vjs-default-skin .vjs-progress-holder .vjs-load-progress { /* Progress Bars */
|
||||||
|
position: absolute; display: block; height: 1.0em; margin: 0; padding: 0;
|
||||||
|
left: 0; top: 0; /*Needed for IE6*/
|
||||||
|
-moz-border-radius: 0.6em; -webkit-border-radius: 0.6em; border-radius: 0.6em;
|
||||||
|
|
||||||
|
/*width: 0;*/
|
||||||
|
}
|
||||||
|
|
||||||
|
.vjs-default-skin .vjs-play-progress {
|
||||||
|
/* CSS Gradient. */
|
||||||
|
background: #fff; /* Old browsers */
|
||||||
|
background: -moz-linear-gradient(top, #fff 0%, #d6d6d6 50%, #fff 100%);
|
||||||
|
background: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(0%,#fff), color-stop(50%,#d6d6d6), color-stop(100%,#fff));
|
||||||
|
background: -webkit-linear-gradient(top, #fff 0%,#d6d6d6 50%,#fff 100%);
|
||||||
|
background: -o-linear-gradient(top, #fff 0%,#d6d6d6 50%,#fff 100%);
|
||||||
|
background: -ms-linear-gradient(top, #fff 0%,#d6d6d6 50%,#fff 100%);
|
||||||
|
background: linear-gradient(top, #fff 0%,#d6d6d6 50%,#fff 100%);
|
||||||
|
|
||||||
|
background: #efefef;
|
||||||
|
background: -moz-linear-gradient(top, #efefef 0%, #f5f5f5 50%, #dbdbdb 50%, #f1f1f1 100%);
|
||||||
|
background: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(0%,#efefef), color-stop(50%,#f5f5f5), color-stop(50%,#dbdbdb), color-stop(100%,#f1f1f1));
|
||||||
|
background: -webkit-linear-gradient(top, #efefef 0%,#f5f5f5 50%,#dbdbdb 50%,#f1f1f1 100%);
|
||||||
|
background: -o-linear-gradient(top, #efefef 0%,#f5f5f5 50%,#dbdbdb 50%,#f1f1f1 100%);
|
||||||
|
background: -ms-linear-gradient(top, #efefef 0%,#f5f5f5 50%,#dbdbdb 50%,#f1f1f1 100%);
|
||||||
|
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#efefef', endColorstr='#f1f1f1',GradientType=0 );
|
||||||
|
background: linear-gradient(top, #efefef 0%,#f5f5f5 50%,#dbdbdb 50%,#f1f1f1 100%);
|
||||||
|
}
|
||||||
|
.vjs-default-skin .vjs-load-progress {
|
||||||
|
opacity: 0.8;
|
||||||
|
|
||||||
|
/* CSS Gradient */
|
||||||
|
background: #666;
|
||||||
|
background: -moz-linear-gradient(top, #666, #333);
|
||||||
|
background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#666), to(#333));
|
||||||
|
background: -webkit-linear-gradient(top, #666, #333);
|
||||||
|
background: -o-linear-gradient(top, #666, #333);
|
||||||
|
background: -ms-linear-gradient(top, #666, #333);
|
||||||
|
background: linear-gradient(top, #666, #333);
|
||||||
|
}
|
||||||
|
|
||||||
|
.vjs-default-skin div.vjs-seek-handle {
|
||||||
|
position: absolute;
|
||||||
|
width: 16px; height: 16px; /* Match img pixles */
|
||||||
|
margin-top: -0.3em;
|
||||||
|
left: 0; top: 0; /*Needed for IE6*/
|
||||||
|
|
||||||
|
background: url('video-js.png') 0 -50px;
|
||||||
|
/* CSS Curved Corners. Needed to make shadows curved. */
|
||||||
|
-moz-border-radius: 0.8em; -webkit-border-radius: 0.8em; border-radius: 0.8em;
|
||||||
|
/* CSS Shadows */
|
||||||
|
-webkit-box-shadow: 0 2px 4px 0 #000; -moz-box-shadow: 0 2px 4px 0 #000; box-shadow: 0 2px 4px 0 #000;
|
||||||
|
}
|
||||||
|
/* Time Display
|
||||||
|
-------------------------------------------------------------------------------- */
|
||||||
|
.vjs-default-skin .vjs-time-controls {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
height: 1.0em; width: 4.8em;
|
||||||
|
top: -1.3em;
|
||||||
|
border-bottom: 1px solid #1F1F1F;
|
||||||
|
border-top: 1px solid #222;
|
||||||
|
background-color: #333;
|
||||||
|
|
||||||
|
font-size: 1em; line-height: 1.0em; font-weight: normal; font-family: Helvetica, Arial, sans-serif;
|
||||||
|
|
||||||
|
background: #333;
|
||||||
|
background: -moz-linear-gradient(top, #222, #333);
|
||||||
|
background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#222), to(#333));
|
||||||
|
background: -webkit-linear-gradient(top, #222, #333);
|
||||||
|
background: -o-linear-gradient(top, #333, #222);
|
||||||
|
background: -ms-linear-gradient(top, #333, #222);
|
||||||
|
background: linear-gradient(top, #333, #222);
|
||||||
|
|
||||||
|
/* 1px top shadow */
|
||||||
|
/* -webkit-box-shadow: 0px -1px 0px 0px rgba(0, 0, 0, 0.15); -moz-box-shadow: 0px -1px 0px 0px rgba(0, 0, 0, 0.15); box-shadow: 0px -1px 0px 0px rgba(0, 0, 0, 0.15);*/
|
||||||
|
}
|
||||||
|
|
||||||
|
.vjs-default-skin .vjs-current-time { left: 0; }
|
||||||
|
|
||||||
|
.vjs-default-skin .vjs-duration { right: 0; display: none; }
|
||||||
|
.vjs-default-skin .vjs-remaining-time { right: 0; }
|
||||||
|
|
||||||
|
.vjs-time-divider { display:none; }
|
||||||
|
|
||||||
|
.vjs-default-skin .vjs-time-control { font-size: 1em; line-height: 1; font-weight: normal; font-family: Helvetica, Arial, sans-serif; }
|
||||||
|
.vjs-default-skin .vjs-time-control span { line-height: 25px; /* Centering vertically */ }
|
||||||
|
|
||||||
|
/* Fullscreen
|
||||||
|
-------------------------------------------------------------------------------- */
|
||||||
|
.vjs-secondary-controls { float: right; }
|
||||||
|
|
||||||
|
.vjs-default-skin .vjs-fullscreen-control { width: 3.8em; cursor: pointer !important; float: right; }
|
||||||
|
.vjs-default-skin .vjs-fullscreen-control div { width: 16px; height: 16px; background: url('video-js.png') -50px 0; margin: 0.5em auto 0; }
|
||||||
|
|
||||||
|
.vjs-default-skin.vjs-fullscreen .vjs-fullscreen-control div { background: url('video-js.png') -75px 0; }
|
||||||
|
|
||||||
|
|
||||||
|
/* Big Play Button (at start)
|
||||||
|
---------------------------------------------------------*/
|
||||||
|
.vjs-default-skin .vjs-big-play-button {
|
||||||
|
display: block; /* Start hidden */ z-index: 2;
|
||||||
|
position: absolute; top: 50%; left: 50%; width: 8.0em; height: 8.0em; margin: -43px 0 0 -43px; text-align: center; vertical-align: center; cursor: pointer !important;
|
||||||
|
border: 0.3em solid #fff; opacity: 0.95;
|
||||||
|
-webkit-border-radius: 25px; -moz-border-radius: 25px; border-radius: 25px;
|
||||||
|
|
||||||
|
background: #454545;
|
||||||
|
background: -moz-linear-gradient(top, #454545 0%, #232323 50%, #161616 50%, #3f3f3f 100%);
|
||||||
|
background: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(0%,#454545), color-stop(50%,#232323), color-stop(50%,#161616), color-stop(100%,#3f3f3f));
|
||||||
|
background: -webkit-linear-gradient(top, #454545 0%,#232323 50%,#161616 50%,#3f3f3f 100%);
|
||||||
|
background: -o-linear-gradient(top, #454545 0%,#232323 50%,#161616 50%,#3f3f3f 100%);
|
||||||
|
background: -ms-linear-gradient(top, #454545 0%,#232323 50%,#161616 50%,#3f3f3f 100%);
|
||||||
|
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#454545', endColorstr='#3f3f3f',GradientType=0 );
|
||||||
|
background: linear-gradient(top, #454545 0%,#232323 50%,#161616 50%,#3f3f3f 100%);
|
||||||
|
|
||||||
|
/* CSS Shadows */
|
||||||
|
-webkit-box-shadow: 4px 4px 8px #000; -moz-box-shadow: 4px 4px 8px #000; box-shadow: 4px 4px 8px #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vjs-default-skin div.vjs-big-play-button:hover {
|
||||||
|
-webkit-box-shadow: 0 0 80px #fff; -moz-box-shadow: 0 0 80px #fff; box-shadow: 0 0 80px #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vjs-default-skin div.vjs-big-play-button span {
|
||||||
|
position: absolute; top: 50%; left: 50%;
|
||||||
|
display: block; width: 35px; height: 42px;
|
||||||
|
margin: -20px 0 0 -15px; /* Using negative margin to center image. */
|
||||||
|
background: url('video-js.png') -100px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Loading Spinner
|
||||||
|
---------------------------------------------------------*/
|
||||||
|
/* CSS Spinners by Kilian Valkhof - http://kilianvalkhof.com/2010/css-xhtml/css3-loading-spinners-without-images/ */
|
||||||
|
.vjs-loading-spinner {
|
||||||
|
display: none;
|
||||||
|
position: absolute; top: 50%; left: 50%; width: 55px; height: 55px;
|
||||||
|
margin: -28px 0 0 -28px;
|
||||||
|
-webkit-animation-name: rotatethis;
|
||||||
|
-webkit-animation-duration:1s;
|
||||||
|
-webkit-animation-iteration-count:infinite;
|
||||||
|
-webkit-animation-timing-function:linear;
|
||||||
|
-moz-animation-name: rotatethis;
|
||||||
|
-moz-animation-duration:1s;
|
||||||
|
-moz-animation-iteration-count:infinite;
|
||||||
|
-moz-animation-timing-function:linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
@-webkit-keyframes rotatethis {
|
||||||
|
0% {-webkit-transform:scale(0.6) rotate(0deg); }
|
||||||
|
12.5% {-webkit-transform:scale(0.6) rotate(0deg); }
|
||||||
|
12.51% {-webkit-transform:scale(0.6) rotate(45deg); }
|
||||||
|
25% {-webkit-transform:scale(0.6) rotate(45deg); }
|
||||||
|
25.01% {-webkit-transform:scale(0.6) rotate(90deg);}
|
||||||
|
37.5% {-webkit-transform:scale(0.6) rotate(90deg);}
|
||||||
|
37.51% {-webkit-transform:scale(0.6) rotate(135deg);}
|
||||||
|
50% {-webkit-transform:scale(0.6) rotate(135deg);}
|
||||||
|
50.01% {-webkit-transform:scale(0.6) rotate(180deg);}
|
||||||
|
62.5% {-webkit-transform:scale(0.6) rotate(180deg);}
|
||||||
|
62.51% {-webkit-transform:scale(0.6) rotate(225deg);}
|
||||||
|
75% {-webkit-transform:scale(0.6) rotate(225deg);}
|
||||||
|
75.01% {-webkit-transform:scale(0.6) rotate(270deg);}
|
||||||
|
87.5% {-webkit-transform:scale(0.6) rotate(270deg);}
|
||||||
|
87.51% {-webkit-transform:scale(0.6) rotate(315deg);}
|
||||||
|
100% {-webkit-transform:scale(0.6) rotate(315deg);}
|
||||||
|
}
|
||||||
|
|
||||||
|
@-moz-keyframes rotatethis {
|
||||||
|
0% {-moz-transform:scale(0.6) rotate(0deg);}
|
||||||
|
12.5% {-moz-transform:scale(0.6) rotate(0deg);}
|
||||||
|
12.51% {-moz-transform:scale(0.6) rotate(45deg);}
|
||||||
|
25% {-moz-transform:scale(0.6) rotate(45deg);}
|
||||||
|
25.01% {-moz-transform:scale(0.6) rotate(90deg);}
|
||||||
|
37.5% {-moz-transform:scale(0.6) rotate(90deg);}
|
||||||
|
37.51% {-moz-transform:scale(0.6) rotate(135deg);}
|
||||||
|
50% {-moz-transform:scale(0.6) rotate(135deg);}
|
||||||
|
50.01% {-moz-transform:scale(0.6) rotate(180deg);}
|
||||||
|
62.5% {-moz-transform:scale(0.6) rotate(180deg);}
|
||||||
|
62.51% {-moz-transform:scale(0.6) rotate(225deg);}
|
||||||
|
75% {-moz-transform:scale(0.6) rotate(225deg);}
|
||||||
|
75.01% {-moz-transform:scale(0.6) rotate(270deg);}
|
||||||
|
87.5% {-moz-transform:scale(0.6) rotate(270deg);}
|
||||||
|
87.51% {-moz-transform:scale(0.6) rotate(315deg);}
|
||||||
|
100% {-moz-transform:scale(0.6) rotate(315deg);}
|
||||||
|
}
|
||||||
|
/* Each circle */
|
||||||
|
div.vjs-loading-spinner .ball1 { opacity: 0.12; position:absolute; left: 20px; top: 0px; width: 13px; height: 13px; background: #fff;
|
||||||
|
border-radius: 13px; -webkit-border-radius: 13px; -moz-border-radius: 13px; border: 1px solid #ccc; }
|
||||||
|
|
||||||
|
div.vjs-loading-spinner .ball2 { opacity: 0.25; position:absolute; left: 34px; top: 6px; width: 13px; height: 13px; background: #fff;
|
||||||
|
border-radius: 13px; -webkit-border-radius: 13px; -moz-border-radius: 13px; border: 1px solid #ccc; }
|
||||||
|
|
||||||
|
div.vjs-loading-spinner .ball3 { opacity: 0.37; position:absolute; left: 40px; top: 20px; width: 13px; height: 13px; background: #fff;
|
||||||
|
border-radius: 13px; -webkit-border-radius: 13px; -moz-border-radius: 13px; border: 1px solid #ccc; }
|
||||||
|
|
||||||
|
div.vjs-loading-spinner .ball4 { opacity: 0.50; position:absolute; left: 34px; top: 34px; width: 13px; height: 13px; background: #fff;
|
||||||
|
border-radius: 10px; -webkit-border-radius: 10px; -moz-border-radius: 15px; border: 1px solid #ccc; }
|
||||||
|
|
||||||
|
div.vjs-loading-spinner .ball5 { opacity: 0.62; position:absolute; left: 20px; top: 40px; width: 13px; height: 13px; background: #fff;
|
||||||
|
border-radius: 13px; -webkit-border-radius: 13px; -moz-border-radius: 13px; border: 1px solid #ccc; }
|
||||||
|
|
||||||
|
div.vjs-loading-spinner .ball6 { opacity: 0.75; position:absolute; left: 6px; top: 34px; width: 13px; height: 13px; background: #fff;
|
||||||
|
border-radius: 13px; -webkit-border-radius: 13px; -moz-border-radius: 13px; border: 1px solid #ccc; }
|
||||||
|
|
||||||
|
div.vjs-loading-spinner .ball7 { opacity: 0.87; position:absolute; left: 0px; top: 20px; width: 13px; height: 13px; background: #fff;
|
||||||
|
border-radius: 13px; -webkit-border-radius: 13px; -moz-border-radius: 13px; border: 1px solid #ccc; }
|
||||||
|
|
||||||
|
div.vjs-loading-spinner .ball8 { opacity: 1.00; position:absolute; left: 6px; top: 6px; width: 13px; height: 13px; background: #fff;
|
||||||
|
border-radius: 13px; -webkit-border-radius: 13px; -moz-border-radius: 13px; border: 1px solid #ccc; }
|
1
extlib/video-js/video-js.min.css
vendored
Normal file
1
extlib/video-js/video-js.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
BIN
extlib/video-js/video-js.png
Normal file
BIN
extlib/video-js/video-js.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.3 KiB |
BIN
extlib/video-js/video-js.swf
Normal file
BIN
extlib/video-js/video-js.swf
Normal file
Binary file not shown.
3744
extlib/video-js/video.js
Normal file
3744
extlib/video-js/video.js
Normal file
File diff suppressed because it is too large
Load Diff
21
extlib/video-js/video.min.js
vendored
Normal file
21
extlib/video-js/video.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@ -120,7 +120,7 @@ def login(request):
|
|||||||
login_failed = False
|
login_failed = False
|
||||||
|
|
||||||
if request.method == 'POST' and login_form.validate():
|
if request.method == 'POST' and login_form.validate():
|
||||||
user = request.db.User.one(
|
user = request.db.User.find_one(
|
||||||
{'username': request.POST['username'].lower()})
|
{'username': request.POST['username'].lower()})
|
||||||
|
|
||||||
if user and user.check_login(request.POST['password']):
|
if user and user.check_login(request.POST['password']):
|
||||||
|
@ -2,6 +2,9 @@
|
|||||||
# HTML title of the pages
|
# HTML title of the pages
|
||||||
html_title = string(default="GNU MediaGoblin")
|
html_title = string(default="GNU MediaGoblin")
|
||||||
|
|
||||||
|
# link to source for this MediaGoblin site
|
||||||
|
source_link = string(default="https://gitorious.org/mediagoblin/mediagoblin")
|
||||||
|
|
||||||
# Enabled media types
|
# Enabled media types
|
||||||
media_types = string_list(default=list("mediagoblin.media_types.image"))
|
media_types = string_list(default=list("mediagoblin.media_types.image"))
|
||||||
|
|
||||||
|
@ -155,6 +155,22 @@ def convert_video_media_data(database):
|
|||||||
collection.save(document)
|
collection.save(document)
|
||||||
|
|
||||||
@RegisterMigration(11)
|
@RegisterMigration(11)
|
||||||
|
def convert_gps_media_data(database):
|
||||||
|
"""
|
||||||
|
Move media_data["gps"]["*"] to media_data["gps_*"].
|
||||||
|
In preparation for media_data.gps_*
|
||||||
|
"""
|
||||||
|
collection = database['media_entries']
|
||||||
|
target = collection.find(
|
||||||
|
{'media_data.gps': {'$exists': True}})
|
||||||
|
|
||||||
|
for document in target:
|
||||||
|
for key, value in document['media_data']['gps'].iteritems():
|
||||||
|
document['media_data']['gps_' + key] = value
|
||||||
|
del document['media_data']['gps']
|
||||||
|
collection.save(document)
|
||||||
|
|
||||||
|
@RegisterMigration(12)
|
||||||
def user_add_wants_comment_notification(database):
|
def user_add_wants_comment_notification(database):
|
||||||
"""
|
"""
|
||||||
Add wants_comment_notification to user model
|
Add wants_comment_notification to user model
|
||||||
|
@ -310,3 +310,9 @@ def check_media_slug_used(db, uploader_id, slug, ignore_m_id):
|
|||||||
existing_user_slug_entries = db.MediaEntry.find(
|
existing_user_slug_entries = db.MediaEntry.find(
|
||||||
query_dict).count()
|
query_dict).count()
|
||||||
return existing_user_slug_entries
|
return existing_user_slug_entries
|
||||||
|
|
||||||
|
|
||||||
|
def media_entries_for_tag_slug(db, tag_slug):
|
||||||
|
return db.MediaEntry.find(
|
||||||
|
{u'state': u'processed',
|
||||||
|
u'tags.slug': tag_slug})
|
||||||
|
@ -14,12 +14,14 @@
|
|||||||
# You should have received a copy of the GNU Affero General Public License
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from copy import copy
|
||||||
|
|
||||||
from mediagoblin.init import setup_global_and_app_config, setup_database
|
from mediagoblin.init import setup_global_and_app_config, setup_database
|
||||||
from mediagoblin.db.mongo.util import ObjectId
|
from mediagoblin.db.mongo.util import ObjectId
|
||||||
|
|
||||||
from mediagoblin.db.sql.models import (Base, User, MediaEntry, MediaComment,
|
from mediagoblin.db.sql.models import (Base, User, MediaEntry, MediaComment,
|
||||||
Tag, MediaTag, MediaFile, MediaAttachmentFile)
|
Tag, MediaTag, MediaFile, MediaAttachmentFile, MigrationData)
|
||||||
|
from mediagoblin.media_types.image.models import ImageData
|
||||||
from mediagoblin.media_types.video.models import VideoData
|
from mediagoblin.media_types.video.models import VideoData
|
||||||
from mediagoblin.db.sql.open import setup_connection_and_db_from_config as \
|
from mediagoblin.db.sql.open import setup_connection_and_db_from_config as \
|
||||||
sql_connect
|
sql_connect
|
||||||
@ -106,6 +108,38 @@ def convert_media_entries(mk_db):
|
|||||||
session.close()
|
session.close()
|
||||||
|
|
||||||
|
|
||||||
|
def convert_image(mk_db):
|
||||||
|
session = Session()
|
||||||
|
|
||||||
|
for media in mk_db.MediaEntry.find(
|
||||||
|
{'media_type': 'mediagoblin.media_types.image'}).sort('created'):
|
||||||
|
media_data = copy(media.media_data)
|
||||||
|
|
||||||
|
# TODO: Fix after exif is migrated
|
||||||
|
media_data.pop('exif', None)
|
||||||
|
|
||||||
|
if len(media_data):
|
||||||
|
media_data_row = ImageData(**media_data)
|
||||||
|
media_data_row.media_entry = obj_id_table[media._id]
|
||||||
|
session.add(media_data_row)
|
||||||
|
|
||||||
|
session.commit()
|
||||||
|
session.close()
|
||||||
|
|
||||||
|
|
||||||
|
def convert_video(mk_db):
|
||||||
|
session = Session()
|
||||||
|
|
||||||
|
for media in mk_db.MediaEntry.find(
|
||||||
|
{'media_type': 'mediagoblin.media_types.video'}).sort('created'):
|
||||||
|
media_data_row = VideoData(**media.media_data)
|
||||||
|
media_data_row.media_entry = obj_id_table[media._id]
|
||||||
|
session.add(media_data_row)
|
||||||
|
|
||||||
|
session.commit()
|
||||||
|
session.close()
|
||||||
|
|
||||||
|
|
||||||
def convert_media_tags(mk_db):
|
def convert_media_tags(mk_db):
|
||||||
session = Session()
|
session = Session()
|
||||||
session.autoflush = False
|
session.autoflush = False
|
||||||
@ -155,6 +189,20 @@ def convert_media_comments(mk_db):
|
|||||||
session.close()
|
session.close()
|
||||||
|
|
||||||
|
|
||||||
|
def convert_add_migration_versions():
|
||||||
|
session = Session()
|
||||||
|
|
||||||
|
for name in ("__main__",
|
||||||
|
"mediagoblin.media_types.image",
|
||||||
|
"mediagoblin.media_types.video",
|
||||||
|
):
|
||||||
|
m = MigrationData(name=name, version=0)
|
||||||
|
session.add(m)
|
||||||
|
|
||||||
|
session.commit()
|
||||||
|
session.close()
|
||||||
|
|
||||||
|
|
||||||
def run_conversion(config_name):
|
def run_conversion(config_name):
|
||||||
global_config, app_config = setup_global_and_app_config(config_name)
|
global_config, app_config = setup_global_and_app_config(config_name)
|
||||||
|
|
||||||
@ -167,10 +215,16 @@ def run_conversion(config_name):
|
|||||||
Session.remove()
|
Session.remove()
|
||||||
convert_media_entries(mk_db)
|
convert_media_entries(mk_db)
|
||||||
Session.remove()
|
Session.remove()
|
||||||
|
convert_image(mk_db)
|
||||||
|
Session.remove()
|
||||||
|
convert_video(mk_db)
|
||||||
|
Session.remove()
|
||||||
convert_media_tags(mk_db)
|
convert_media_tags(mk_db)
|
||||||
Session.remove()
|
Session.remove()
|
||||||
convert_media_comments(mk_db)
|
convert_media_comments(mk_db)
|
||||||
Session.remove()
|
Session.remove()
|
||||||
|
convert_add_migration_versions()
|
||||||
|
Session.remove()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
@ -20,6 +20,7 @@ TODO: indexes on foreignkeys, where useful.
|
|||||||
|
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
|
import sys
|
||||||
|
|
||||||
from sqlalchemy import (
|
from sqlalchemy import (
|
||||||
Column, Integer, Unicode, UnicodeText, DateTime, Boolean, ForeignKey,
|
Column, Integer, Unicode, UnicodeText, DateTime, Boolean, ForeignKey,
|
||||||
@ -28,10 +29,12 @@ from sqlalchemy.orm import relationship
|
|||||||
from sqlalchemy.orm.collections import attribute_mapped_collection
|
from sqlalchemy.orm.collections import attribute_mapped_collection
|
||||||
from sqlalchemy.sql.expression import desc
|
from sqlalchemy.sql.expression import desc
|
||||||
from sqlalchemy.ext.associationproxy import association_proxy
|
from sqlalchemy.ext.associationproxy import association_proxy
|
||||||
|
from sqlalchemy.util import memoized_property
|
||||||
|
|
||||||
from mediagoblin.db.sql.extratypes import PathTupleWithSlashes, JSONEncoded
|
from mediagoblin.db.sql.extratypes import PathTupleWithSlashes, JSONEncoded
|
||||||
from mediagoblin.db.sql.base import Base, DictReadAttrProxy
|
from mediagoblin.db.sql.base import Base, DictReadAttrProxy
|
||||||
from mediagoblin.db.mixin import UserMixin, MediaEntryMixin, MediaCommentMixin
|
from mediagoblin.db.mixin import UserMixin, MediaEntryMixin, MediaCommentMixin
|
||||||
|
from mediagoblin.db.sql.base import Session
|
||||||
|
|
||||||
# It's actually kind of annoying how sqlalchemy-migrate does this, if
|
# It's actually kind of annoying how sqlalchemy-migrate does this, if
|
||||||
# I understand it right, but whatever. Anyway, don't remove this :P
|
# I understand it right, but whatever. Anyway, don't remove this :P
|
||||||
@ -58,7 +61,7 @@ class User(Base, UserMixin):
|
|||||||
TODO: We should consider moving some rarely used fields
|
TODO: We should consider moving some rarely used fields
|
||||||
into some sort of "shadow" table.
|
into some sort of "shadow" table.
|
||||||
"""
|
"""
|
||||||
__tablename__ = "users"
|
__tablename__ = "core__users"
|
||||||
|
|
||||||
id = Column(Integer, primary_key=True)
|
id = Column(Integer, primary_key=True)
|
||||||
username = Column(Unicode, nullable=False, unique=True)
|
username = Column(Unicode, nullable=False, unique=True)
|
||||||
@ -85,10 +88,10 @@ class MediaEntry(Base, MediaEntryMixin):
|
|||||||
"""
|
"""
|
||||||
TODO: Consider fetching the media_files using join
|
TODO: Consider fetching the media_files using join
|
||||||
"""
|
"""
|
||||||
__tablename__ = "media_entries"
|
__tablename__ = "core__media_entries"
|
||||||
|
|
||||||
id = Column(Integer, primary_key=True)
|
id = Column(Integer, primary_key=True)
|
||||||
uploader = Column(Integer, ForeignKey('users.id'), nullable=False)
|
uploader = Column(Integer, ForeignKey('core__users.id'), nullable=False)
|
||||||
title = Column(Unicode, nullable=False)
|
title = Column(Unicode, nullable=False)
|
||||||
slug = Column(Unicode)
|
slug = Column(Unicode)
|
||||||
created = Column(DateTime, nullable=False, default=datetime.datetime.now)
|
created = Column(DateTime, nullable=False, default=datetime.datetime.now)
|
||||||
@ -168,14 +171,39 @@ class MediaEntry(Base, MediaEntryMixin):
|
|||||||
if media is not None:
|
if media is not None:
|
||||||
return media.url_for_self(urlgen)
|
return media.url_for_self(urlgen)
|
||||||
|
|
||||||
|
#@memoized_property
|
||||||
@property
|
@property
|
||||||
def media_data(self):
|
def media_data(self):
|
||||||
# TODO: Replace with proper code to read the correct table
|
session = Session()
|
||||||
return {}
|
|
||||||
|
return session.query(self.media_data_table).filter_by(
|
||||||
|
media_entry=self.id).first()
|
||||||
|
|
||||||
def media_data_init(self, **kwargs):
|
def media_data_init(self, **kwargs):
|
||||||
# TODO: Implement this
|
"""
|
||||||
pass
|
Initialize or update the contents of a media entry's media_data row
|
||||||
|
"""
|
||||||
|
session = Session()
|
||||||
|
|
||||||
|
media_data = session.query(self.media_data_table).filter_by(
|
||||||
|
media_entry=self.id).first()
|
||||||
|
|
||||||
|
# No media data, so actually add a new one
|
||||||
|
if not media_data:
|
||||||
|
media_data = self.media_data_table(
|
||||||
|
**kwargs)
|
||||||
|
session.add(media_data)
|
||||||
|
# Update old media data
|
||||||
|
else:
|
||||||
|
for field, value in kwargs.iteritems():
|
||||||
|
setattr(media_data, field, value)
|
||||||
|
|
||||||
|
@memoized_property
|
||||||
|
def media_data_table(self):
|
||||||
|
# TODO: memoize this
|
||||||
|
models_module = self.media_type + '.models'
|
||||||
|
__import__(models_module)
|
||||||
|
return sys.modules[models_module].DATA_MODEL
|
||||||
|
|
||||||
|
|
||||||
class FileKeynames(Base):
|
class FileKeynames(Base):
|
||||||
@ -203,7 +231,7 @@ class MediaFile(Base):
|
|||||||
TODO: Highly consider moving "name" into a new table.
|
TODO: Highly consider moving "name" into a new table.
|
||||||
TODO: Consider preloading said table in software
|
TODO: Consider preloading said table in software
|
||||||
"""
|
"""
|
||||||
__tablename__ = "mediafiles"
|
__tablename__ = "core__mediafiles"
|
||||||
|
|
||||||
media_entry = Column(
|
media_entry = Column(
|
||||||
Integer, ForeignKey(MediaEntry.id),
|
Integer, ForeignKey(MediaEntry.id),
|
||||||
@ -242,7 +270,7 @@ class MediaAttachmentFile(Base):
|
|||||||
|
|
||||||
|
|
||||||
class Tag(Base):
|
class Tag(Base):
|
||||||
__tablename__ = "tags"
|
__tablename__ = "core__tags"
|
||||||
|
|
||||||
id = Column(Integer, primary_key=True)
|
id = Column(Integer, primary_key=True)
|
||||||
slug = Column(Unicode, nullable=False, unique=True)
|
slug = Column(Unicode, nullable=False, unique=True)
|
||||||
@ -259,13 +287,13 @@ class Tag(Base):
|
|||||||
|
|
||||||
|
|
||||||
class MediaTag(Base):
|
class MediaTag(Base):
|
||||||
__tablename__ = "media_tags"
|
__tablename__ = "core__media_tags"
|
||||||
|
|
||||||
id = Column(Integer, primary_key=True)
|
id = Column(Integer, primary_key=True)
|
||||||
media_entry = Column(
|
media_entry = Column(
|
||||||
Integer, ForeignKey(MediaEntry.id),
|
Integer, ForeignKey(MediaEntry.id),
|
||||||
nullable=False)
|
nullable=False)
|
||||||
tag = Column(Integer, ForeignKey('tags.id'), nullable=False)
|
tag = Column(Integer, ForeignKey('core__tags.id'), nullable=False)
|
||||||
name = Column(Unicode)
|
name = Column(Unicode)
|
||||||
# created = Column(DateTime, nullable=False, default=datetime.datetime.now)
|
# created = Column(DateTime, nullable=False, default=datetime.datetime.now)
|
||||||
|
|
||||||
@ -292,12 +320,12 @@ class MediaTag(Base):
|
|||||||
|
|
||||||
|
|
||||||
class MediaComment(Base, MediaCommentMixin):
|
class MediaComment(Base, MediaCommentMixin):
|
||||||
__tablename__ = "media_comments"
|
__tablename__ = "core__media_comments"
|
||||||
|
|
||||||
id = Column(Integer, primary_key=True)
|
id = Column(Integer, primary_key=True)
|
||||||
media_entry = Column(
|
media_entry = Column(
|
||||||
Integer, ForeignKey('media_entries.id'), nullable=False)
|
Integer, ForeignKey('core__media_entries.id'), nullable=False)
|
||||||
author = Column(Integer, ForeignKey('users.id'), nullable=False)
|
author = Column(Integer, ForeignKey('core__users.id'), nullable=False)
|
||||||
created = Column(DateTime, nullable=False, default=datetime.datetime.now)
|
created = Column(DateTime, nullable=False, default=datetime.datetime.now)
|
||||||
content = Column(UnicodeText, nullable=False)
|
content = Column(UnicodeText, nullable=False)
|
||||||
|
|
||||||
@ -319,7 +347,7 @@ MODELS = [
|
|||||||
######################################################
|
######################################################
|
||||||
|
|
||||||
class MigrationData(Base):
|
class MigrationData(Base):
|
||||||
__tablename__ = "migrations"
|
__tablename__ = "core__migrations"
|
||||||
|
|
||||||
name = Column(Unicode, primary_key=True)
|
name = Column(Unicode, primary_key=True)
|
||||||
version = Column(Integer, nullable=False, default=0)
|
version = Column(Integer, nullable=False, default=0)
|
||||||
|
@ -294,6 +294,15 @@ def check_media_slug_used(dummy_db, uploader_id, slug, ignore_m_id):
|
|||||||
return does_exist
|
return does_exist
|
||||||
|
|
||||||
|
|
||||||
|
def media_entries_for_tag_slug(dummy_db, tag_slug):
|
||||||
|
return MediaEntry.query \
|
||||||
|
.join(MediaEntry.tags_helper) \
|
||||||
|
.join(MediaTag.tag_helper) \
|
||||||
|
.filter(
|
||||||
|
(MediaEntry.state == u'processed')
|
||||||
|
& (Tag.slug == tag_slug))
|
||||||
|
|
||||||
|
|
||||||
def clean_orphan_tags():
|
def clean_orphan_tags():
|
||||||
q1 = Session.query(Tag).outerjoin(MediaTag).filter(MediaTag.id==None)
|
q1 = Session.query(Tag).outerjoin(MediaTag).filter(MediaTag.id==None)
|
||||||
for t in q1:
|
for t in q1:
|
||||||
|
@ -21,7 +21,9 @@ except ImportError:
|
|||||||
|
|
||||||
if use_sql:
|
if use_sql:
|
||||||
from mediagoblin.db.sql.fake import ObjectId, InvalidId, DESCENDING
|
from mediagoblin.db.sql.fake import ObjectId, InvalidId, DESCENDING
|
||||||
from mediagoblin.db.sql.util import atomic_update, check_media_slug_used
|
from mediagoblin.db.sql.util import atomic_update, check_media_slug_used, \
|
||||||
|
media_entries_for_tag_slug
|
||||||
else:
|
else:
|
||||||
from mediagoblin.db.mongo.util import \
|
from mediagoblin.db.mongo.util import \
|
||||||
ObjectId, InvalidId, DESCENDING, atomic_update, check_media_slug_used
|
ObjectId, InvalidId, DESCENDING, atomic_update, \
|
||||||
|
check_media_slug_used, media_entries_for_tag_slug
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
import sys
|
import sys
|
||||||
|
|
||||||
from mediagoblin.db.mongo import util as db_util
|
from mediagoblin.db.mongo import util as db_util
|
||||||
from mediagoblin.db.open import setup_connection_and_db_from_config
|
from mediagoblin.db.mongo.open import setup_connection_and_db_from_config
|
||||||
from mediagoblin.init import setup_global_and_app_config
|
from mediagoblin.init import setup_global_and_app_config
|
||||||
|
|
||||||
# This MUST be imported so as to set up the appropriate migrations!
|
# This MUST be imported so as to set up the appropriate migrations!
|
||||||
@ -41,7 +41,12 @@ def _print_finished_migration(migration_number, migration_func):
|
|||||||
|
|
||||||
|
|
||||||
def migrate(args):
|
def migrate(args):
|
||||||
global_config, app_config = setup_global_and_app_config(args.conf_file)
|
run_migrate(args.conf_file)
|
||||||
|
|
||||||
|
|
||||||
|
def run_migrate(conf_file):
|
||||||
|
global_config, app_config = setup_global_and_app_config(conf_file)
|
||||||
|
|
||||||
connection, db = setup_connection_and_db_from_config(
|
connection, db = setup_connection_and_db_from_config(
|
||||||
app_config, use_pymongo=True)
|
app_config, use_pymongo=True)
|
||||||
migration_manager = db_util.MigrationManager(db)
|
migration_manager = db_util.MigrationManager(db)
|
||||||
|
@ -14,12 +14,15 @@
|
|||||||
# You should have received a copy of the GNU Affero General Public License
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
from mediagoblin.db.sql.convert import run_conversion
|
|
||||||
|
|
||||||
|
|
||||||
def mongosql_parser_setup(subparser):
|
def mongosql_parser_setup(subparser):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def mongosql(args):
|
def mongosql(args):
|
||||||
|
# First, make sure our mongo migrations are up to date...
|
||||||
|
from mediagoblin.gmg_commands.migrate import run_migrate
|
||||||
|
run_migrate(args.conf_file)
|
||||||
|
|
||||||
|
from mediagoblin.db.sql.convert import run_conversion
|
||||||
run_conversion(args.conf_file)
|
run_conversion(args.conf_file)
|
||||||
|
@ -22,7 +22,9 @@ from mediagoblin.gmg_commands import util as commands_util
|
|||||||
|
|
||||||
|
|
||||||
def shell_parser_setup(subparser):
|
def shell_parser_setup(subparser):
|
||||||
pass
|
subparser.add_argument(
|
||||||
|
'--ipython', help='Use ipython',
|
||||||
|
action="store_true")
|
||||||
|
|
||||||
|
|
||||||
SHELL_BANNER = """\
|
SHELL_BANNER = """\
|
||||||
@ -34,16 +36,42 @@ Available vars:
|
|||||||
- db: database instance
|
- db: database instance
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
def py_shell(**user_namespace):
|
||||||
|
"""
|
||||||
|
Run a shell using normal python shell.
|
||||||
|
"""
|
||||||
|
code.interact(
|
||||||
|
banner=SHELL_BANNER,
|
||||||
|
local=user_namespace)
|
||||||
|
|
||||||
|
|
||||||
|
def ipython_shell(**user_namespace):
|
||||||
|
"""
|
||||||
|
Run a shell for the user using ipython.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
from IPython import embed
|
||||||
|
except:
|
||||||
|
print "IPython not available... exiting!"
|
||||||
|
return
|
||||||
|
|
||||||
|
embed(
|
||||||
|
banner1=SHELL_BANNER,
|
||||||
|
user_ns=user_namespace)
|
||||||
|
|
||||||
|
|
||||||
def shell(args):
|
def shell(args):
|
||||||
"""
|
"""
|
||||||
Setup a shell for the user
|
Setup a shell for the user
|
||||||
|
either a normal Python shell
|
||||||
|
or an IPython one
|
||||||
"""
|
"""
|
||||||
mgoblin_app = commands_util.setup_app(args)
|
user_namespace = {
|
||||||
|
'mg_globals': mg_globals,
|
||||||
|
'mgoblin_app': commands_util.setup_app(args),
|
||||||
|
'db': mg_globals.database}
|
||||||
|
|
||||||
code.interact(
|
if args.ipython:
|
||||||
banner=SHELL_BANNER,
|
ipython_shell(**user_namespace)
|
||||||
local={
|
else:
|
||||||
'mgoblin_app': mgoblin_app,
|
py_shell(**user_namespace)
|
||||||
'mg_globals': mg_globals,
|
|
||||||
'db': mg_globals.database})
|
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
# You should have received a copy of the GNU Affero General Public License
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
from mediagoblin.db.util import DESCENDING
|
from mediagoblin.db.util import media_entries_for_tag_slug, DESCENDING
|
||||||
|
|
||||||
from mediagoblin.tools.pagination import Pagination
|
from mediagoblin.tools.pagination import Pagination
|
||||||
from mediagoblin.tools.response import render_to_response
|
from mediagoblin.tools.response import render_to_response
|
||||||
@ -29,11 +29,16 @@ def _get_tag_name_from_entries(media_entries, tag_slug):
|
|||||||
"""
|
"""
|
||||||
# ... this is slightly hacky looking :\
|
# ... this is slightly hacky looking :\
|
||||||
tag_name = tag_slug
|
tag_name = tag_slug
|
||||||
if media_entries.count():
|
|
||||||
for tag in media_entries[0]['tags']:
|
for entry in media_entries:
|
||||||
|
for tag in entry.tags:
|
||||||
if tag['slug'] == tag_slug:
|
if tag['slug'] == tag_slug:
|
||||||
tag_name == tag['name']
|
tag_name = tag['name']
|
||||||
break
|
break
|
||||||
|
break
|
||||||
|
# TODO: Remove after SQL-switch, it's mongo specific
|
||||||
|
if hasattr(media_entries, "rewind"):
|
||||||
|
media_entries.rewind()
|
||||||
|
|
||||||
return tag_name
|
return tag_name
|
||||||
|
|
||||||
@ -43,9 +48,7 @@ def tag_listing(request, page):
|
|||||||
"""'Gallery'/listing for this tag slug"""
|
"""'Gallery'/listing for this tag slug"""
|
||||||
tag_slug = request.matchdict[u'tag']
|
tag_slug = request.matchdict[u'tag']
|
||||||
|
|
||||||
cursor = request.db.MediaEntry.find(
|
cursor = media_entries_for_tag_slug(request.db, tag_slug)
|
||||||
{u'state': u'processed',
|
|
||||||
u'tags.slug': tag_slug})
|
|
||||||
cursor = cursor.sort('created', DESCENDING)
|
cursor = cursor.sort('created', DESCENDING)
|
||||||
|
|
||||||
pagination = Pagination(page, cursor)
|
pagination = Pagination(page, cursor)
|
||||||
|
@ -23,11 +23,11 @@ from sqlalchemy import (
|
|||||||
|
|
||||||
|
|
||||||
class AsciiData(Base):
|
class AsciiData(Base):
|
||||||
__tablename__ = "ascii_data"
|
__tablename__ = "ascii__mediadata"
|
||||||
|
|
||||||
id = Column(Integer, primary_key=True)
|
id = Column(Integer, primary_key=True)
|
||||||
media_entry = Column(
|
media_entry = Column(
|
||||||
Integer, ForeignKey('media_entries.id'), nullable=False)
|
Integer, ForeignKey('core__media_entries.id'), nullable=False)
|
||||||
|
|
||||||
|
|
||||||
DATA_MODEL = AsciiData
|
DATA_MODEL = AsciiData
|
||||||
|
@ -5,15 +5,17 @@ from sqlalchemy import (
|
|||||||
|
|
||||||
|
|
||||||
class ImageData(Base):
|
class ImageData(Base):
|
||||||
__tablename__ = "image_data"
|
__tablename__ = "image__mediadata"
|
||||||
|
|
||||||
# The primary key *and* reference to the main media_entry
|
# The primary key *and* reference to the main media_entry
|
||||||
media_entry = Column(Integer, ForeignKey('media_entries.id'),
|
media_entry = Column(Integer, ForeignKey('core__media_entries.id'),
|
||||||
primary_key=True)
|
primary_key=True)
|
||||||
width = Column(Integer)
|
width = Column(Integer)
|
||||||
height = Column(Integer)
|
height = Column(Integer)
|
||||||
gps_longitude = Column(Float)
|
gps_longitude = Column(Float)
|
||||||
gps_latitude = Column(Float)
|
gps_latitude = Column(Float)
|
||||||
|
gps_altitude = Column(Float)
|
||||||
|
gps_direction = Column(Float)
|
||||||
|
|
||||||
|
|
||||||
DATA_MODEL = ImageData
|
DATA_MODEL = ImageData
|
||||||
|
@ -115,11 +115,18 @@ def process_image(entry):
|
|||||||
|
|
||||||
# Insert exif data into database
|
# Insert exif data into database
|
||||||
media_data = entry.setdefault('media_data', {})
|
media_data = entry.setdefault('media_data', {})
|
||||||
media_data['exif'] = {
|
|
||||||
'clean': clean_exif(exif_tags)}
|
# TODO: Fix for sql media_data, when exif is in sql
|
||||||
media_data['exif']['useful'] = get_useful(
|
if media_data is not None:
|
||||||
media_data['exif']['clean'])
|
media_data['exif'] = {
|
||||||
media_data['gps'] = gps_data
|
'clean': clean_exif(exif_tags)}
|
||||||
|
media_data['exif']['useful'] = get_useful(
|
||||||
|
media_data['exif']['clean'])
|
||||||
|
|
||||||
|
if len(gps_data):
|
||||||
|
for key in list(gps_data.keys()):
|
||||||
|
gps_data['gps_' + key] = gps_data.pop(key)
|
||||||
|
entry.media_data_init(**gps_data)
|
||||||
|
|
||||||
# clean up workbench
|
# clean up workbench
|
||||||
workbench.destroy_self()
|
workbench.destroy_self()
|
||||||
|
@ -22,10 +22,10 @@ from sqlalchemy import (
|
|||||||
|
|
||||||
|
|
||||||
class VideoData(Base):
|
class VideoData(Base):
|
||||||
__tablename__ = "video_data"
|
__tablename__ = "video__mediadata"
|
||||||
|
|
||||||
# The primary key *and* reference to the main media_entry
|
# The primary key *and* reference to the main media_entry
|
||||||
media_entry = Column(Integer, ForeignKey('media_entries.id'),
|
media_entry = Column(Integer, ForeignKey('core__media_entries.id'),
|
||||||
primary_key=True)
|
primary_key=True)
|
||||||
width = Column(SmallInteger)
|
width = Column(SmallInteger)
|
||||||
height = Column(SmallInteger)
|
height = Column(SmallInteger)
|
||||||
|
@ -234,13 +234,14 @@ text-align: center;
|
|||||||
height: 0;
|
height: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
h3.sidedata {
|
.media_sidebar h3 {
|
||||||
border: none;
|
|
||||||
background-color: #212121;
|
|
||||||
border-radius: 4px 4px 0 0;
|
|
||||||
padding: 3px 8px;
|
|
||||||
margin: 20px 0 5px 0;
|
|
||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
|
margin: 0 0 5px;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.media_sidebar p {
|
||||||
|
padding-left: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* forms */
|
/* forms */
|
||||||
|
1
mediagoblin/static/js/extlib/video-js
Symbolic link
1
mediagoblin/static/js/extlib/video-js
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../../../../extlib/video-js
|
@ -82,7 +82,10 @@
|
|||||||
{% block mediagoblin_footer %}
|
{% block mediagoblin_footer %}
|
||||||
<footer>
|
<footer>
|
||||||
{% trans -%}
|
{% trans -%}
|
||||||
Powered by <a href="http://mediagoblin.org">MediaGoblin</a>, a <a href="http://gnu.org/">GNU</a> project
|
Powered by <a href="http://mediagoblin.org">MediaGoblin</a>, a <a href="http://gnu.org/">GNU</a> project.
|
||||||
|
{%- endtrans %}
|
||||||
|
{% trans source_link=app_config['source_link'] -%}
|
||||||
|
Released under the <a href="http://www.fsf.org/licensing/licenses/agpl-3.0.html">AGPL</a>. <a href="{{ source_link }}">Source code</a> available.
|
||||||
{%- endtrans %}
|
{%- endtrans %}
|
||||||
</footer>
|
</footer>
|
||||||
{% endblock mediagoblin_footer %}
|
{% endblock mediagoblin_footer %}
|
||||||
|
@ -18,6 +18,13 @@
|
|||||||
|
|
||||||
{% extends 'mediagoblin/user_pages/media.html' %}
|
{% extends 'mediagoblin/user_pages/media.html' %}
|
||||||
|
|
||||||
|
{% block mediagoblin_head %}
|
||||||
|
{{ super() }}
|
||||||
|
<script type="text/javascript"
|
||||||
|
src="{{ request.staticdirect('/js/extlib/video-js/video.js') }}"></script>
|
||||||
|
<link href="{{ request.staticdirect('/js/extlib/video-js/video-js.css') }}" rel="stylesheet">
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
{% block mediagoblin_media %}
|
{% block mediagoblin_media %}
|
||||||
<div class="video-player" style="position: relative;">
|
<div class="video-player" style="position: relative;">
|
||||||
<video class="video-js vjs-default-skin"
|
<video class="video-js vjs-default-skin"
|
||||||
|
@ -172,7 +172,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="media_sidebar">
|
<div class="media_sidebar">
|
||||||
{% trans date=media.created.strftime("%Y-%m-%d") -%}
|
{% trans date=media.created.strftime("%Y-%m-%d") -%}
|
||||||
<h3 class="sidedata">Added on</h3>
|
<h3>Added on</h3>
|
||||||
<p>{{ date }}</p>
|
<p>{{ date }}</p>
|
||||||
{%- endtrans %}
|
{%- endtrans %}
|
||||||
{% if media.tags %}
|
{% if media.tags %}
|
||||||
|
@ -17,10 +17,10 @@
|
|||||||
#}
|
#}
|
||||||
|
|
||||||
{% block exif_content %}
|
{% block exif_content %}
|
||||||
{% if media.media_data.has_key('exif')
|
{% if app_config['exif_visible']
|
||||||
and app_config['exif_visible']
|
and media.media_data.exif is defined
|
||||||
and media.media_data.exif.has_key('useful') %}
|
and media.media_data.exif.has_key('useful') %}
|
||||||
<h3 class="sidedata">EXIF</h3>
|
<h3>EXIF</h3>
|
||||||
<table>
|
<table>
|
||||||
{% for key, tag in media.media_data.exif.useful.items() %}
|
{% for key, tag in media.media_data.exif.useful.items() %}
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -17,24 +17,27 @@
|
|||||||
#}
|
#}
|
||||||
|
|
||||||
{% block geolocation_map %}
|
{% block geolocation_map %}
|
||||||
{% if media.media_data.has_key('gps')
|
{% if app_config['geolocation_map_visible']
|
||||||
and app_config['geolocation_map_visible']
|
and media.media_data.gps_latitude is defined
|
||||||
and media.media_data.gps %}
|
and media.media_data.gps_latitude
|
||||||
<h3 class="sidedata">Location</h3>
|
and media.media_data.gps_longitude is defined
|
||||||
|
and media.media_data.gps_longitude %}
|
||||||
|
<h3>{% trans %}Location{% endtrans %}</h3>
|
||||||
<div>
|
<div>
|
||||||
{% set gps = media.media_data.gps %}
|
{%- set lon = media.media_data.gps_longitude %}
|
||||||
|
{%- set lat = media.media_data.gps_latitude %}
|
||||||
|
{%- set osm_url = "http://openstreetmap.org/?mlat={lat}&mlon={lon}".format(lat=lat, lon=lon) %}
|
||||||
<div id="tile-map" style="width: 100%; height: 196px;">
|
<div id="tile-map" style="width: 100%; height: 196px;">
|
||||||
<input type="hidden" id="gps-longitude"
|
<input type="hidden" id="gps-longitude"
|
||||||
value="{{ gps.longitude }}" />
|
value="{{ lon }}" />
|
||||||
<input type="hidden" id="gps-latitude"
|
<input type="hidden" id="gps-latitude"
|
||||||
value="{{ gps.latitude }}" />
|
value="{{ lat }}" />
|
||||||
</div>
|
</div>
|
||||||
<p>
|
<p>
|
||||||
<small>
|
<small>
|
||||||
View on
|
{% trans -%}
|
||||||
<a href="http://openstreetmap.org/?mlat={{ gps.latitude }}&mlon={{ gps.longitude }}">
|
View on <a href="{{ osm_url }}">OpenStreetMap</a>
|
||||||
OpenStreetMap
|
{%- endtrans %}
|
||||||
</a>
|
|
||||||
</small>
|
</small>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
#}
|
#}
|
||||||
|
|
||||||
{% block license_content -%}
|
{% block license_content -%}
|
||||||
<h3 class="sidedata">{% trans %}License{% endtrans %}</h3>
|
<h3>{% trans %}License{% endtrans %}</h3>
|
||||||
<p>
|
<p>
|
||||||
{% if media.license %}
|
{% if media.license %}
|
||||||
<a href="{{ media.license }}">{{ media.get_license_data().abbreviation }}</a>
|
<a href="{{ media.license }}">{{ media.get_license_data().abbreviation }}</a>
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
#}
|
#}
|
||||||
|
|
||||||
{% block tags_content -%}
|
{% block tags_content -%}
|
||||||
<h3 class="sidedata">Tagged with</h3>
|
<h3>{% trans %}Tagged with{% endtrans %}</h3>
|
||||||
<p>
|
<p>
|
||||||
{% for tag in media.tags %}
|
{% for tag in media.tags %}
|
||||||
{% if loop.last %}
|
{% if loop.last %}
|
||||||
|
@ -180,6 +180,18 @@ class TestSubmission:
|
|||||||
# Does media entry exist?
|
# Does media entry exist?
|
||||||
assert_true(media)
|
assert_true(media)
|
||||||
|
|
||||||
|
# Add a comment, so we can test for its deletion later.
|
||||||
|
get_comments = lambda: list(
|
||||||
|
request.db.MediaComment.find({'media_entry': media._id}))
|
||||||
|
assert_false(get_comments())
|
||||||
|
response = self.test_app.post(
|
||||||
|
request.urlgen('mediagoblin.user_pages.media_post_comment',
|
||||||
|
user=self.test_user.username,
|
||||||
|
media=media._id),
|
||||||
|
{'comment_content': 'i love this test'})
|
||||||
|
response.follow()
|
||||||
|
assert_true(get_comments())
|
||||||
|
|
||||||
# Do not confirm deletion
|
# Do not confirm deletion
|
||||||
# ---------------------------------------------------
|
# ---------------------------------------------------
|
||||||
response = self.test_app.post(
|
response = self.test_app.post(
|
||||||
@ -219,6 +231,9 @@ class TestSubmission:
|
|||||||
request.db.MediaEntry.find(
|
request.db.MediaEntry.find(
|
||||||
{'_id': media._id}).count())
|
{'_id': media._id}).count())
|
||||||
|
|
||||||
|
# How about the comment?
|
||||||
|
assert_false(get_comments())
|
||||||
|
|
||||||
def test_malicious_uploads(self):
|
def test_malicious_uploads(self):
|
||||||
# Test non-suppoerted file with non-supported extension
|
# Test non-suppoerted file with non-supported extension
|
||||||
# -----------------------------------------------------
|
# -----------------------------------------------------
|
||||||
|
@ -14,8 +14,12 @@
|
|||||||
# You should have received a copy of the GNU Affero General Public License
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import logging
|
||||||
from mediagoblin.db.util import ObjectId, InvalidId
|
from mediagoblin.db.util import ObjectId, InvalidId
|
||||||
|
|
||||||
|
_log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def setup_user_in_request(request):
|
def setup_user_in_request(request):
|
||||||
"""
|
"""
|
||||||
Examine a request and tack on a request.user parameter if that's
|
Examine a request and tack on a request.user parameter if that's
|
||||||
@ -30,12 +34,12 @@ def setup_user_in_request(request):
|
|||||||
except InvalidId:
|
except InvalidId:
|
||||||
user = None
|
user = None
|
||||||
else:
|
else:
|
||||||
user = request.db.User.one({'_id': oid})
|
user = request.db.User.find_one({'_id': oid})
|
||||||
|
|
||||||
if not user:
|
if not user:
|
||||||
# Something's wrong... this user doesn't exist? Invalidate
|
# Something's wrong... this user doesn't exist? Invalidate
|
||||||
# this session.
|
# this session.
|
||||||
print "Killing session for %r" % request.session['user_id']
|
_log.warn("Killing session for user id %r", request.session['user_id'])
|
||||||
request.session.invalidate()
|
request.session.invalidate()
|
||||||
|
|
||||||
request.user = user
|
request.user = user
|
||||||
|
@ -21,7 +21,7 @@ from mediagoblin.tools.translate import fake_ugettext_passthrough as _
|
|||||||
|
|
||||||
class MediaCommentForm(wtforms.Form):
|
class MediaCommentForm(wtforms.Form):
|
||||||
comment_content = wtforms.TextAreaField(
|
comment_content = wtforms.TextAreaField(
|
||||||
_(''),
|
'',
|
||||||
[wtforms.validators.Required()])
|
[wtforms.validators.Required()])
|
||||||
|
|
||||||
|
|
||||||
|
@ -180,6 +180,10 @@ def media_confirm_delete(request, media):
|
|||||||
if form.confirm.data is True:
|
if form.confirm.data is True:
|
||||||
username = media.get_uploader.username
|
username = media.get_uploader.username
|
||||||
|
|
||||||
|
# Delete all the associated comments
|
||||||
|
for comment in media.get_comments():
|
||||||
|
comment.delete()
|
||||||
|
|
||||||
# Delete all files on the public storage
|
# Delete all files on the public storage
|
||||||
delete_media_files(media)
|
delete_media_files(media)
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user