diff --git a/pandora/app/config.py b/pandora/app/config.py index 41c97808..a3ba295c 100644 --- a/pandora/app/config.py +++ b/pandora/app/config.py @@ -39,9 +39,8 @@ def load_config(): config['keys'][key['id']] = key settings.CONFIG = config - admin = len(settings.CONFIG['userLevels']) - 1 - if not 'syncdb' in sys.argv: + if not 'syncdb' in sys.argv and not 'sqldiff' in sys.argv: settings.ADMIN = tuple([(u.username, u.email) for u in User.objects.filter(profile__level=admin)]) settings.MANAGERS = settings.ADMINS diff --git a/pandora/padma.jsonc b/pandora/padma.jsonc index 1041bc38..33b555ab 100644 --- a/pandora/padma.jsonc +++ b/pandora/padma.jsonc @@ -1,16 +1,87 @@ +/* + Pan.do/ra Settings + + You can edit this file. +*/ { - "groups": [ - {"id": "director", "title": "Director"}, - {"id": "collection", "title": "Collection"}, - {"id": "year", "title": "Year"}, - {"id": "language", "title": "Language"}, - {"id": "category", "title": "Category"}, - {"id": "contributor", "title": "Contributor"}, - {"id": "cinematographer", "title": "Cinematographer"}, - {"id": "source", "title": "Source"}, - {"id": "keyword", "title": "Keyword"} + /* + Capabilities are per user level. + They can either be general: + {level: true} means a user of that level has the capability) + or related to items: + {level: x} means a user of that level has the capability + for items of a rights level up to and including x + */ + "capabilities": { + // "canClickMap": {"friend": true, "staff": true, "admin": true}, + "canDeleteItems": {"admin": true}, + "canDownloadVideo": {"guest": 0, "member": 0, "friend": 4, "staff": 4, "admin": 4}, + "canEditFeaturedLists": {"staff": true, "admin": true}, + "canEditMetadata": {"staff": true, "admin": true}, + "canEditSitePages": {"staff": true, "admin": true}, + "canEditUsers": {"admin": true}, + "canPlayClips": {"guest": 2, "member": 2, "friend": 4, "staff": 4, "admin": 4}, + "canPlayVideo": {"guest": 1, "member": 1, "friend": 4, "staff": 4, "admin": 4}, + "canSeeDebugMenu": {"staff": true, "admin": true}, + "canSeeFiles": {"staff": true, "admin": true}, + "canSeeItem": {"guest": 3, "member": 3, "friend": 4, "staff": 4, "admin": 4}, + "canSeeExtraItemViews": {"friend": true, "staff": true, "admin": true} + }, + /* + clipKeys are the properties that clips can by sorted by. + If sortOperator is not specified, it will be + for strings and - for numbers. + */ + "clipKeys": [ + {"id": "text", "title": "Text", "type": "string"}, + {"id": "position", "title": "Position", "type": "float", "sortOperator": "+"}, + {"id": "duration", "title": "Duration", "type": "float"}, + {"id": "hue", "title": "Hue", "type": "float", "sortOperator": "+"}, + {"id": "saturation", "title": "Saturation", "type": "float"}, + {"id": "lightness", "title": "Lightness", "type": "float"}, + {"id": "volume", "title": "Volume", "type": "float"} ], + // fixme: either this, or filter: true in itemKeys, but not both + "filters": [ + {"id": "director", "title": "Director", "type": "string"}, + {"id": "country", "title": "Country", "type": "string"}, + {"id": "year", "title": "Year", "type": "integer"}, + {"id": "language", "title": "Language", "type": "string"}, + {"id": "source", "title": "Source", "type": "string"}, + {"id": "writer", "title": "Writer", "type": "string"}, + {"id": "producer", "title": "Producer", "type": "string"}, + {"id": "cinematographer", "title": "Cinematographer", "type": "string"}, + {"id": "editor", "title": "Editor", "type": "string"}, + {"id": "actor", "title": "Actor", "type": "string"}, + {"id": "keyword", "title": "Keyword", "type": "string"} + ], + /* + An itemKey must have the following properties: + id: The id of the key (as known by the server) + title: The title of the key (as displayed by the client) + type: text, string, float, integer, or array of any of these + and can have any of the following properties: + autocomplete: If true, find element will autocomplete + autocompleteSortKey: The key that suggestions will be sorted by + capability: A capability required to see this key + columnRequired: If true, the column can't be removed + columnWidth: Default column width in px + find: If true, will appear as a find option + filter: if true, one can filter results by this key + format: {type: "...", args: [...]}, for special formatting + (Ox.formatType(args) will be called) + sort: special sort rule (title, person) + sortOperator: sort operator (+, -), in case it differs from the + default for the key's type (+ for strings, - for numbers) + value: {key: "...", type: "..."}, for keys that are derived + from other keys (like number of actors), or "capability" + */ "itemKeys": [ + { + "id": "*", + "title": "All", + "type": "text", + "find": true + }, { "id": "title", "title": "Title", @@ -29,8 +100,8 @@ "autocomplete": true, "columnRequired": true, "columnWidth": 180, + "filter": true, "find": true, - "group": true, "sort": "person" }, { @@ -39,8 +110,8 @@ "type": "string", "autocomplete": true, "columnWidth": 120, - "find": true, - "group": true + "filter": true, + "find": true }, { "id": "year", @@ -48,8 +119,8 @@ "type": "year", "autocomplete": true, "columnWidth": 60, - "find": true, - "group": true + "filter": true, + "find": true }, { "id": "language", @@ -57,13 +128,13 @@ "type": ["string"], "autocomplete": true, "columnWidth": 120, - "find": true, - "group": true + "filter": true, + "find": true }, { "id": "runtime", "title": "Runtime", - "type": "integer", + "type": "time", "columnWidth": 60, "format": {"type": "duration", "args": [0, "medium"]} }, @@ -73,8 +144,8 @@ "type": "string", "autocomplete": true, "columnWidth": 180, - "find": true, - "group": true + "filter": true, + "find": true }, { "id": "genre", @@ -82,16 +153,16 @@ "type": ["string"], "autocomplete": true, "columnWidth": 120, - "find": true, - "group": true + "filter": true, + "find": true }, { "id": "keyword", "title": "Keyword", "type": ["string"], "autocomplete": true, - "find": true, - "group": true + "filter": true, + "find": true }, { "id": "numberofkeywords", @@ -280,6 +351,17 @@ "type": "integer", "columnWidth": 60 }, + { + "id": "rightslevel", + "title": "Rights Level", + "type": "enum", + "columnWidth": 90, + "format": {"type": "ColorLevel", "args": [ + ["Public", "Relaxed", "Regular", "Restricted", "Private"] + ]}, + "sortOperator": "+", + "values": ["Public", "Relaxed", "Regular", "Restricted", "Private", "Unknown"] + } ], "itemName": { "singular": "Video", @@ -287,12 +369,13 @@ }, "itemViews": [ {"id": "info", "title": "Info"}, - {"id": "statistics", "title": "Statistics"}, {"id": "clips", "title": "Clips"}, - {"id": "player", "title": "Player"}, + {"id": "video", "title": "Video"}, {"id": "timeline", "title": "Timeline"}, {"id": "map", "title": "Map"}, - {"id": "calendar", "title": "Calendar"} + {"id": "calendar", "title": "Calendar"}, + {"id": "data", "title": "Data"}, + {"id": "files", "title": "Files"} ], "layers": [ { @@ -324,12 +407,13 @@ "listViews": [ {"id": "list", "title": "as List"}, {"id": "icons", "title": "as Icons"}, - {"id": "info", "title": "with Info"}, + //{"id": "info", "title": "with Info"}, {"id": "clips", "title": "with Clips"}, {"id": "timelines", "title": "with Timelines"}, {"id": "maps", "title": "with Maps"}, {"id": "calendars", "title": "with Calendars"}, {"id": "clip", "title": "as Clips"}, + //{"id": "video", "title": "as Video"}, {"id": "map", "title": "on Map"}, {"id": "calendar", "title": "on Calendar"} ], @@ -337,7 +421,23 @@ "importMoviePosters": false, "importPosterFrames": false }, + "personalLists": [ + {"title": "Favorites"} + ], + "rightsLevel": {"member": 2, "staff": 2, "admin": 2}, + "rightsLevels": [ + {"name": "Public", "color": [128, 255, 128]}, + {"name": "Restricted", "color": [255, 192, 128]}, + {"name": "Private", "color": [255, 128, 128]} + ], + "sendReferrer": true, "site": { + "email": { + // E-mail address in contact form (to) + "contact": "pad.ma@pad.ma", + // E-mail address uses by the system (from) + "system": "system@pad.ma" + }, "id": "padma", "name": "Pad.ma", "url": "pad.ma", @@ -346,10 +446,11 @@ "sitePages": [ {"id": "about", "title": "About"}, {"id": "news", "title": "News"}, - {"id": "tour", "title": "Take a Tour"}, + //{"id": "tour", "title": "Take a Tour"}, {"id": "faq", "title": "Frequently Asked Questions"}, {"id": "terms", "title": "Terms of Service"}, - {"id": "license", "title": "License"} + {"id": "license", "title": "License"}, + {"id": "contact", "title": "Contact"} ], "totals": [ {"id": "items"}, @@ -361,73 +462,72 @@ ], "user": { "level": "guest", - "lists": { - "history": [ - {"id": "all_movies", "title": "All Movies", "query": {}} - ], - "personal": [ - {"user": "foo", "name": "Favorites", "featured": false, "public": true}, - {"id": "favorites", "title": "Favorites", "public": true, "items": []}, - {"id": "most_popular", "title": "Most Popular", "query": {}}, - {"id": "recently_viewed", "title": "Recently Viewed", "query": {}}, - {"id": "1960s", "title": "1960s", "query": {"conditions": [{"key": "year", "value": "196", "operator": "^"}], "operator": ""}} - ], - "favorite": [ - {"id": "rlx:watchme", "title": "rlx: watchme", "public": true, "items": [0, 1, 2, 3, 4]} - ], - "featured": [ - {"id": "situationist_film", "title": "Situationist Film", "query": {}}, - {"id": "timelines", "title": "Timelines", "items": [0, 1, 2, 3, 4, 5, 6, 7, 8]} - ] - }, "ui": { "annotationsSize": 256, - "find": {"index": -1, "key": "", "value": ""}, - "groups": ["director", "collection", "source", "language", "category"], - "groupsQuery": {"conditions": [], "operator": "|"}, - "groupsSize": 176, - "item": "", - "itemView": "timeline", - "list": "", - "lists": { - "": { - "columns": ["title", "director", "country", "year", "language", "runtime", "genre"], - "columnWidth": {}, - "listView": "icons", - "selected": [], - "sort": [ - {"key": "director", "operator": ""} - ] + "clipsColumns": 2, + "columns": { + "Colors": { + "columns": ["title", "director", "country", "year", "hue", "saturation", "brightness"], + "columnWidth": {} } }, - "query": {"conditions": [], "operator": ""}, + "filters": [ + {"id": "director", "sort": [{"key": "items", "operator": "-"}]}, + {"id": "country", "sort": [{"key": "items", "operator": "-"}]}, + {"id": "year", "sort": [{"key": "name", "operator": "-"}]}, + {"id": "language", "sort": [{"key": "items", "operator": "-"}]}, + {"id": "source", "sort": [{"key": "items", "operator": "-"}]} + ], + "filtersSize": 176, + "find": {"conditions": [], "operator": "&"}, + "icons": "posters", + "infoIconSize": 256, + "item": "", + "itemFind": {"conditions": [], "operator": "&"}, + "itemSort": [{"key": "position", "operator": "+"}], + "itemView": "info", + "listColumns": ["title", "director", "country", "year", "language", "duration", "source"], + "listColumnWidth": {}, + "listSelection": [], + "listSort": [{"key": "director", "operator": "+"}], + "listView": "grid", + "lists": {}, + "mapFind": "", + "mapSelection": "", + "page": "", "section": "items", "showAnnotations": true, - "showControls": true, - "showGroups": true, + "showBrowser": true, + "showCalendarControls": true, // fixme: should be false + "showFilters": true, + "showFlags": true, + "showHome": true, + "showIconBrowser": false, "showInfo": true, - "showMovies": true, + "showMapControls": false, + "showMapLabels": false, "showFolder": { - "site": { - "site": true, - "user": true, - "admin": true - }, "items": { "personal": true, "favorite": true, - "featured": true + "featured": true, + "volumes": true } }, "showSidebar": true, + "showSitePosters": false, + "showTimeline": true, "sidebarSize": 256, - "sitePage": "home", "theme": "classic", - "videoPosition": {}, - "videoScreen": "fit", - "videoSize": "small" + "videoPoints": {}, + "videoScale": "fit", + "videoMuted": false, + "videoSize": "small", + "videoView": "video", + "videoVolume": 1 }, - "username": "" + "username": "", + "volumes": [] }, "userLevels": ["guest", "member", "staff", "admin"], "video": { diff --git a/static/js/pandora/utils.js b/static/js/pandora/utils.js index 99384251..7dc4dc4b 100644 --- a/static/js/pandora/utils.js +++ b/static/js/pandora/utils.js @@ -76,6 +76,9 @@ pandora.addList = function() { }); } function getPosterFrames(newList) { + var sortKey = Ox.getObjectById(pandora.site.itemKeys, 'votes') + ? 'votes' + : 'timesaccessed'; if (!isDuplicate) { pandora.api.find({ query: { @@ -83,7 +86,7 @@ pandora.addList = function() { operator: '&' }, keys: ['id', 'posterFrame'], - sort: [{key: 'votes', operator: ''}], // fixme: may not always exist + sort: [{key: sortKey, operator: ''}], range: [0, 4] }, function(result) { var posterFrames = result.data.items.map(function(item) { @@ -557,6 +560,9 @@ pandora.getInfoHeight = function(includeHidden) { } pandora.getItemByIdOrTitle = function(str, callback) { + var sortKey = Ox.getObjectById(pandora.site.itemKeys, 'votes') + ? 'votes' + : 'timesaccessed'; pandora.api.get({id: str, keys: ['id']}, function(result) { if (result.status.code == 200) { callback(result.data.id); @@ -566,9 +572,9 @@ pandora.getItemByIdOrTitle = function(str, callback) { conditions: [{key: 'title', value: str, operator: '='}], operator: '&' }, - sort: [{key: 'votes', operator: ''}], // fixme: not all systems have "votes" + sort: [{key: sortKey, operator: ''}], range: [0, 100], - keys: ['id', 'title', 'votes'] + keys: ['id', 'title', sortKey] }, function(result) { var id = ''; if (result.data.items.length) { @@ -576,7 +582,7 @@ pandora.getItemByIdOrTitle = function(str, callback) { // test if exact match or word match var sort = new RegExp('^' + str + '$', 'i').test(item.title) ? 2000000 : new RegExp('\\b' + str + '\\b', 'i').test(item.title) ? 1000000 : 0; - return sort ? {id: item.id, sort: sort + (parseInt(item.votes) || 0)} : null; + return sort ? {id: item.id, sort: sort + (parseInt(item[sortKey]) || 0)} : null; // fixme: remove the (...|| 0) check once the backend sends correct data }); if (items.length) {