function getFirstTextLine(commentString) { if (!commentString) { return; } var lines = commentString.split('\n'); var MARKDOWN_CHARS = { '#': true, '-': true, '>': true, '`': true }; for (var i = 0; i < lines.length; ++i) { // Skip code lines. if (lines[i].indexOf(' ') == 0) { continue; } // Skip empty lines. if ($.trim(lines[i]).length == 0) { continue; } // Skip control lines. if (MARKDOWN_CHARS[$.trim(lines[i])[0]]) { continue; } return getMarkedDown(lines[i]); } return ''; } function getMarkedDown(string) { return Markdown.getSanitizingConverter().makeHtml(string || ''); } function HeaderCtrl($scope, UserService) { $scope.$watch( function () { return UserService.currentUser(); }, function (currentUser) { $scope.user = currentUser; }, true); $('#repoSearch').typeahead({ name: 'repositories', remote: { url: '/api/find/repository?query=%QUERY', filter: function(data) { var datums = []; for (var i = 0; i < data.repositories.length; ++i) { var repo = data.repositories[i]; datums.push({ 'value': repo.name, 'tokens': [repo.name, repo.namespace], 'repo': repo }); } return datums; } }, template: function (datum) { template = '
'; template += '' template += '' + datum.repo.namespace +'/' + datum.repo.name + '' if (datum.repo.description) { template += '' + getFirstTextLine(datum.repo.description) + '' } template += '
' return template; }, }); $('#repoSearch').on('typeahead:selected', function (e, datum) { $('#repoSearch').typeahead('setQuery', ''); document.location = '#/repository/' + datum.repo.namespace + '/' + datum.repo.name }); } function GuideCtrl($scope, Restangular) { } function RepoListCtrl($scope, Restangular, UserService) { $scope.$watch( function () { return UserService.currentUser(); }, function (currentUser) { $scope.user = currentUser; }, true); $scope.getCommentFirstLine = function(commentString) { return getMarkedDown(getFirstTextLine(commentString)); }; $scope.getMarkedDown = function(string) { if (!string) { return ''; } return getMarkedDown(string); }; $('.spin').spin(); $scope.loading = true; $scope.public_repositories = null; $scope.private_repositories = null; // Load the list of personal repositories. var repositoryPrivateFetch = Restangular.all('repository/'); repositoryPrivateFetch.getList({'public': false, 'sort': true}).then(function(resp) { $scope.private_repositories = resp.repositories; $scope.loading = !($scope.public_repositories && $scope.private_repositories); }); // Load the list of public repositories. var options = {'public': true, 'private': false, 'sort': true, 'limit': 10}; var repositoryPublicFetch = Restangular.all('repository/'); repositoryPublicFetch.getList(options).then(function(resp) { $scope.public_repositories = resp.repositories; $scope.loading = !($scope.public_repositories && $scope.private_repositories); }); } function LandingCtrl($scope, $timeout, Restangular, UserService) { $('.form-signup').popover(); $('.spin').spin(); $scope.$watch( function () { return UserService.currentUser(); }, function (currentUser) { if (!currentUser.anonymous) { $scope.loadMyRepos(); } $scope.user = currentUser; }, true); $scope.awaitingConfirmation = false; $scope.registering = false; $scope.getCommentFirstLine = function(commentString) { return getMarkedDown(getFirstTextLine(commentString)); }; $scope.browseRepos = function() { document.location = '/#/repository'; }; $scope.register = function() { $('.form-signup').popover('hide'); $scope.registering = true; var newUserPost = Restangular.one('user/'); newUserPost.customPOST($scope.newUser).then(function() { $scope.awaitingConfirmation = true; $scope.registering = false; }, function(result) { console.log("Displaying error message."); $scope.registering = false; $scope.registerError = result.data.message; $timeout(function() { $('.form-signup').popover('show'); }); }); }; $scope.loadMyRepos = function() { $scope.loadingmyrepos = true; // Load the list of repositories. var params = { 'limit': 5, 'public': false, 'sort': true }; var repositoryFetch = Restangular.all('repository/'); repositoryFetch.getList(params).then(function(resp) { $scope.myrepos = resp.repositories; $scope.loadingmyrepos = false; }); }; } function RepoCtrl($scope, Restangular, $routeParams, $rootScope) { var tabs = ['current-image', 'image-history']; $rootScope.title = 'Loading...'; $scope.showTab = function(tabName) { for (var i = 0; i < tabs.length; ++i) { $('#' + tabs[i]).hide(); $('#' + tabs[i] + '-tab').removeClass('active'); } $('#' + tabName).show(); $('#' + tabName + '-tab').addClass('active'); if (tabName == 'image-history') { $scope.listImages(); } }; $scope.editDescription = function() { if (!$scope.repo.can_write) { return; } if (!$scope.markdownDescriptionEditor) { var converter = Markdown.getSanitizingConverter(); var editor = new Markdown.Editor(converter, '-description'); editor.run(); $scope.markdownDescriptionEditor = editor; } $('#wmd-input-description')[0].value = $scope.repo.description; $('#editModal').modal({}); }; $scope.saveDescription = function() { $('#editModal').modal('hide'); $scope.repo.description = $('#wmd-input-description')[0].value; $scope.repo.put(); }; $scope.parseDate = function(dateString) { return Date.parse(dateString); }; $scope.getCommentFirstLine = function(commentString) { return getMarkedDown(getFirstTextLine(commentString)); }; $scope.getMarkedDown = function(string) { if (!string) { return ''; } return getMarkedDown(string); }; $scope.listImages = function() { if ($scope.imageHistory) { return; } var imageFetch = Restangular.one('repository/' + namespace + '/' + name + '/tag/' + $scope.currentTag.name + '/images'); imageFetch.get().then(function(resp) { $scope.imageHistory = resp.images; }); }; $scope.getTagCount = function(repo) { if (!repo) { return 0; } var count = 0; for (var tag in repo.tags) { ++count; } return count; }; var namespace = $routeParams.namespace; var name = $routeParams.name; var tag = $routeParams.tag || 'latest'; $('.spin').spin(); $scope.loading = true; var repositoryFetch = Restangular.one('repository/' + namespace + '/' + name); repositoryFetch.get().then(function(repo) { $rootScope.title = namespace + '/' + name; $scope.repo = repo; $scope.currentTag = repo.tags[tag] || repo.tags['latest']; var clip = new ZeroClipboard($('#copyClipboard'), { 'moviePath': 'static/lib/ZeroClipboard.swf' }); clip.on('complete', function() { // Resets the animation. var elem = $('#clipboardCopied')[0]; elem.style.display = 'none'; // Show the notification. setTimeout(function() { elem.style.display = 'block'; }, 1); }); $scope.loading = false; }, function() { $scope.repo = null; $scope.loading = false; $rootScope.title = 'Unknown Repository'; }); } function RepoAdminCtrl($scope, Restangular, $routeParams, $rootScope) { var namespace = $routeParams.namespace; var name = $routeParams.name; $('#userSearch').typeahead({ name: 'users', remote: { url: '/api/users/%QUERY', filter: function(data) { var datums = []; for (var i = 0; i < data.users.length; ++i) { var user = data.users[i]; datums.push({ 'value': user, 'tokens': [user], 'username': user }); } return datums; } }, template: function (datum) { template = '
'; template += '' template += '' + datum.username + '' template += '
' return template; }, }); $('#userSearch').on('typeahead:selected', function(e, datum) { $('#userSearch').typeahead('setQuery', ''); $scope.addNewPermission(datum.username); }); $scope.addNewPermission = function(username) { // Don't allow duplicates. if ($scope.permissions[username]) { return; } // Need the $scope.apply for both the permission stuff to change and for // the XHR call to be made. $scope.$apply(function() { $scope.addRole(username, 'read') }); }; $scope.deleteRole = function(username) { var permissionDelete = Restangular.one('repository/' + namespace + '/' + name + '/permissions/' + username); permissionDelete.customDELETE().then(function() { delete $scope.permissions[username]; }, function(result) { if (result.status == 409) { $('#onlyadminModal').modal({}); } else { $('#cannotchangeModal').modal({}); } }); }; $scope.addRole = function(username, role) { var permission = { 'role': role }; var permissionPost = Restangular.one('repository/' + namespace + '/' + name + '/permissions/' + username); permissionPost.customPOST(permission).then(function() { $scope.permissions[username] = permission; $scope.permissions = $scope.permissions; }, function(result) { $('#cannotchangeModal').modal({}); }); }; $scope.setRole = function(username, role) { var permission = $scope.permissions[username]; var currentRole = permission.role; permission.role = role; var permissionPut = Restangular.one('repository/' + namespace + '/' + name + '/permissions/' + username); permissionPut.customPUT(permission).then(function() {}, function(result) { if (result.status == 409) { permission.role = currentRole; $('#onlyadminModal').modal({}); } else { $('#cannotchangeModal').modal({}); } }); }; $scope.askChangeAccess = function(newAccess) { $('#make' + newAccess + 'Modal').modal({}); }; $scope.changeAccess = function(newAccess) { $('#make' + newAccess + 'Modal').modal('hide'); var visibility = { 'visibility': newAccess }; var visibilityPost = Restangular.one('repository/' + namespace + '/' + name + '/changevisibility'); visibilityPost.customPOST(visibility).then(function() { $scope.repo.is_public = newAccess == 'public'; }, function() { $('#cannotchangeModal').modal({}); }); }; $scope.askDelete = function() { $('#confirmdeleteModal').modal({}); }; $scope.deleteRepo = function() { $('#confirmdeleteModal').modal('hide'); var deleteAction = Restangular.one('repository/' + namespace + '/' + name); deleteAction.customDELETE().then(function() { $scope.repo = null; setTimeout(function() { document.location = '/#/repository'; }, 1000); }, function() { $('#cannotchangeModal').modal({}); }); }; $('.spin').spin(); $scope.loading = true; // Fetch the repository information. var repositoryFetch = Restangular.one('repository/' + namespace + '/' + name); repositoryFetch.get().then(function(repo) { $scope.repo = repo; $scope.loading = !($scope.permissions && $scope.repo); }, function() { $scope.permissions = null; $rootScope.title = 'Unknown Repository'; $scope.loading = false; }); // Fetch the permissions. var permissionsFetch = Restangular.one('repository/' + namespace + '/' + name + '/permissions'); permissionsFetch.get().then(function(resp) { $rootScope.title = 'Settings - ' + namespace + '/' + name; $scope.permissions = resp.permissions; $scope.loading = !($scope.permissions && $scope.repo); }, function() { $scope.permissions = null; $rootScope.title = 'Unknown Repository'; $scope.loading = false; }); } function UserAdminCtrl($scope, Restangular) { $scope.plans = [ { title: 'Micro', price: 700, privateRepos: 5, stripeId: 'micro', }, { title: 'Small', price: 1200, privateRepos: 10, stripeId: 'small', }, { title: 'Medium', price: 2200, privateRepos: 20, stripeId: 'medium', }, ]; var planDict = {}; var i; for(i = 0; i < $scope.plans.length; i++) { planDict[$scope.plans[i].stripeId] = $scope.plans[i]; } $('.spin').spin(); var subscribedToPlan = function(sub) { $scope.subscription = sub; $scope.subscribedPlan = planDict[sub.plan]; $scope.planUsagePercent = sub.usedPrivateRepos * 100 / $scope.subscribedPlan.privateRepos; $scope.planLoading = false; $scope.planChanging = false; } $scope.planLoading = true; var getSubscription = Restangular.one('user/plan'); getSubscription.get().then(subscribedToPlan, function() { // User has no subscription $scope.planLoading = false; }); $scope.planChanging = false; $scope.subscribe = function(planId) { var submitToken = function(token) { $scope.$apply(function() { $scope.planChanging = true; $scope.errorMessage = undefined; var subscriptionDetails = { token: token.id, plan: planId, }; console.log(subscriptionDetails); var createSubscriptionRequest = Restangular.one('user/plan'); createSubscriptionRequest.customPUT(subscriptionDetails).then(subscribedToPlan, function() { // Failure $scope.errorMessage = 'Unable to subscribe.'; }); }); }; console.log('Got request for plan: ' + planId); var planDetails = planDict[planId] StripeCheckout.open({ key: 'pk_test_uEDHANKm9CHCvVa2DLcipGRh', address: false, // TODO change to true amount: planDetails.price, currency: 'usd', name: 'Quay ' + planDetails.title + ' Subscription', description: 'Up to ' + planDetails.privateRepos + ' private repositories', panelLabel: 'Subscribe', token: submitToken }); }; $scope.changeSubscription = function(planId) { $scope.planChanging = true; $scope.errorMessage = undefined; var subscriptionDetails = { plan: planId, }; var changeSubscriptionRequest = Restangular.one('user/plan'); changeSubscriptionRequest.customPUT(subscriptionDetails).then(subscribedToPlan, function() { // Failure $scope.errorMessage = 'Unable to change subscription.'; $scope.planChanging = false; }); }; $scope.cancelSubscription = function() { $scope.planChanging = true; $scope.errorMessage = undefined; var unsubscribeRequest = Restangular.one('user/plan'); unsubscribeRequest.customDELETE().then(function() { $scope.subscription = undefined; $scope.subscribedPlan = undefined; $scope.planUsagePercent = 0; $scope.planChanging = false; }, function() { // Failure $scope.errorMessage = 'Unable to unsubscribe.'; $scope.planChanging = false; }); }; }