Allow sync manually, instead force sync at ever login

This commit is contained in:
Kirill Zaitsev 2014-10-28 18:16:50 +03:00
parent 09b4d6038d
commit eef53530c1
9 changed files with 156 additions and 51 deletions

View file

@ -198,10 +198,23 @@ app.run(['$location', '$rootScope', '$routeParams', 'feed', 'stdout', function($
app.controller("AccountReposController", function($scope, $http, user) { app.controller("AccountReposController", function($scope, $http, $location, user) {
$scope.user = user; $scope.user = user;
$scope.syncUser = function() {
$http({method: 'POST', url: '/api/user/sync' }).success(function(data){
$location.search('return_to', $location.$$path).path('/sync')
}).error(function(data, status){
if (status == 409) {
$scope.msg = 'already'
} else {
$scope.msg = 'bad'
}
$scope.$apply();
});
}
// get the user details // get the user details
$http({method: 'GET', url: '/api/user/repos'}). $http({method: 'GET', url: '/api/user/repos'}).
success(function(data, status, headers, config) { success(function(data, status, headers, config) {

View file

@ -1,6 +1,6 @@
'use strict'; 'use strict';
angular.module('app').controller("HomeController", function($scope, $http, feed) { angular.module('app').controller("HomeController", function($scope, $http, $location, feed) {
feed.subscribe(function(item) { feed.subscribe(function(item) {
// todo toast notification // todo toast notification
@ -14,6 +14,19 @@ angular.module('app').controller("HomeController", function($scope, $http, feed)
console.log(data); console.log(data);
}); });
$scope.syncUser = function() {
$http({method: 'POST', url: '/api/user/sync' }).success(function(data){
$location.search('return_to', $location.$$path).path('/sync')
}).error(function(data, status){
if (status == 409) {
$scope.msg = 'already'
} else {
$scope.msg = 'bad'
}
$scope.$apply();
});
}
$http({method: 'GET', url: '/api/user/repos'}). $http({method: 'GET', url: '/api/user/repos'}).
success(function(data, status, headers, config) { success(function(data, status, headers, config) {
$scope.repos = (typeof data==='string')?[]:data; $scope.repos = (typeof data==='string')?[]:data;

View file

@ -1,10 +1,16 @@
'use strict'; 'use strict';
angular.module('app').controller("SyncController", function($scope, $http, $interval, $location, users) { angular.module('app').controller("SyncController", function($scope, $http, $interval, $location, $routeParams, users) {
var return_to = $routeParams.return_to
var stop = $interval(function() { var stop = $interval(function() {
// todo(bradrydzewski) We should poll the user to see if the // todo(bradrydzewski) We should poll the user to see if the
// sync process is complete, using the user.syncing variable. // sync process is complete, using the user.syncing variable.
$interval.cancel(stop); $interval.cancel(stop);
$location.path("/"); if (return_to != undefined) {
$location.$$search = {}
$location.path(return_to);
} else {
$location.path("/");
}
}, 5000); }, 5000);
}); });

View file

@ -1,7 +1,18 @@
<div class="toast" ng-if="msg != undefined">
<span ng-if="msg == 'already'">sync already runned</span>
<span ng-if="msg == 'bad'">bad response</span>
</div>
<article id="homepage"> <article id="homepage">
<nav> <nav>
<a href="/"><span class="fa fa-th"></span></a> <a href="/"><span class="fa fa-th"></span></a>
<a href="/">dashboard</a> <a href="/">dashboard</a>
<div class="options ng-scope">
<a class="pure-button pure-button-primary" ng-click="syncUser()" href="#">
<i class="fa fa-refresh"></i>
<span>Sync</span>
</a>
</div>
</nav> </nav>
<section ng-if="feed.length == 0"> <section ng-if="feed.length == 0">

View file

@ -1,7 +1,19 @@
<div class="toast" ng-if="msg != undefined">
<span ng-if="msg == 'already'">sync already runned</span>
<span ng-if="msg == 'bad'">bad response</span>
</div>
<div id="repospage"> <div id="repospage">
<nav> <nav>
<a href="/"><span class="fa fa-th"></span></a> <a href="/"><span class="fa fa-th"></span></a>
<a href="/">repositories</a> <a href="/">repositories</a>
<div class="options ng-scope">
<a class="pure-button pure-button-primary" ng-click="syncUser()" href="#">
<i class="fa fa-refresh"></i>
<span>Sync</span>
</a>
</div>
</nav> </nav>
<section> <section>

View file

@ -4,12 +4,12 @@ import (
"encoding/json" "encoding/json"
"log" "log"
"net/http" "net/http"
"time"
"github.com/drone/drone/plugin/remote" "github.com/drone/drone/plugin/remote"
"github.com/drone/drone/server/capability" "github.com/drone/drone/server/capability"
"github.com/drone/drone/server/datastore" "github.com/drone/drone/server/datastore"
"github.com/drone/drone/server/session" "github.com/drone/drone/server/session"
"github.com/drone/drone/server/sync"
"github.com/drone/drone/shared/model" "github.com/drone/drone/shared/model"
"github.com/goji/context" "github.com/goji/context"
"github.com/zenazn/goji/web" "github.com/zenazn/goji/web"
@ -83,7 +83,8 @@ func GetLogin(c web.C, w http.ResponseWriter, r *http.Request) {
u.Secret = login.Secret u.Secret = login.Secret
u.Name = login.Name u.Name = login.Name
u.SetEmail(login.Email) u.SetEmail(login.Email)
u.Syncing = true //u.IsStale() // todo (badrydzewski) should not always sync u.Syncing = u.IsStale()
if err := datastore.PutUser(ctx, u); err != nil { if err := datastore.PutUser(ctx, u); err != nil {
log.Println(err) log.Println(err)
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusBadRequest)
@ -102,51 +103,8 @@ func GetLogin(c web.C, w http.ResponseWriter, r *http.Request) {
redirect = "/sync" redirect = "/sync"
log.Println("sync user account.", u.Login) log.Println("sync user account.", u.Login)
// sync inside a goroutine. This should eventually be moved to // sync inside a goroutine
// its own package / sync utility. go sync.SyncUser(ctx, u, remote)
go func() {
repos, err := remote.GetRepos(u)
if err != nil {
log.Println("Error syncing user account, listing repositories", u.Login, err)
return
}
// insert all repositories
for _, repo := range repos {
var role = repo.Role
if err := datastore.PostRepo(ctx, repo); err != nil {
// typically we see a failure because the repository already exists
// in which case, we can retrieve the existing record to get the ID.
repo, err = datastore.GetRepoName(ctx, repo.Host, repo.Owner, repo.Name)
if err != nil {
log.Println("Error adding repo.", u.Login, repo.Name, err)
continue
}
}
// add user permissions
perm := model.Perm{
UserID: u.ID,
RepoID: repo.ID,
Read: role.Read,
Write: role.Write,
Admin: role.Admin,
}
if err := datastore.PostPerm(ctx, &perm); err != nil {
log.Println("Error adding permissions.", u.Login, repo.Name, err)
continue
}
log.Println("Successfully syced repo.", u.Login+"/"+repo.Name)
}
u.Synced = time.Now().UTC().Unix()
u.Syncing = false
if err := datastore.PutUser(ctx, u); err != nil {
log.Println("Error syncing user account, updating sync date", u.Login, err)
return
}
}()
} }
token, err := session.GenerateToken(ctx, r, u) token, err := session.GenerateToken(ctx, r, u)

View file

@ -4,7 +4,9 @@ import (
"encoding/json" "encoding/json"
"net/http" "net/http"
"github.com/drone/drone/plugin/remote"
"github.com/drone/drone/server/datastore" "github.com/drone/drone/server/datastore"
"github.com/drone/drone/server/sync"
"github.com/drone/drone/shared/model" "github.com/drone/drone/shared/model"
"github.com/goji/context" "github.com/goji/context"
"github.com/zenazn/goji/web" "github.com/zenazn/goji/web"
@ -111,3 +113,37 @@ func GetUserFeed(c web.C, w http.ResponseWriter, r *http.Request) {
} }
json.NewEncoder(w).Encode(&repos) json.NewEncoder(w).Encode(&repos)
} }
// PostUserSync accepts a request to post user sync
//
// POST /api/user/sync
//
func PostUserSync(c web.C, w http.ResponseWriter, r *http.Request) {
var ctx = context.FromC(c)
var user = ToUser(c)
if user == nil {
w.WriteHeader(http.StatusUnauthorized)
return
}
var remote = remote.Lookup(user.Remote)
if remote == nil {
w.WriteHeader(http.StatusNotFound)
return
}
if user.Syncing {
w.WriteHeader(http.StatusConflict)
return
}
user.Syncing = true
if err := datastore.PutUser(ctx, user); err != nil {
w.WriteHeader(http.StatusNotFound)
return
}
go sync.SyncUser(ctx, user, remote)
w.WriteHeader(http.StatusNoContent)
return
}

View file

@ -58,6 +58,7 @@ func New() *web.Mux {
user.Use(middleware.RequireUser) user.Use(middleware.RequireUser)
user.Get("/api/user/feed", handler.GetUserFeed) user.Get("/api/user/feed", handler.GetUserFeed)
user.Get("/api/user/repos", handler.GetUserRepos) user.Get("/api/user/repos", handler.GetUserRepos)
user.Post("/api/user/sync", handler.PostUserSync)
user.Get("/api/user", handler.GetUserCurrent) user.Get("/api/user", handler.GetUserCurrent)
user.Put("/api/user", handler.PutUser) user.Put("/api/user", handler.PutUser)
mux.Handle("/api/user*", user) mux.Handle("/api/user*", user)

55
server/sync/sync.go Normal file
View file

@ -0,0 +1,55 @@
package sync
import (
"log"
"time"
"code.google.com/p/go.net/context"
"github.com/drone/drone/plugin/remote"
"github.com/drone/drone/server/datastore"
"github.com/drone/drone/shared/model"
)
func SyncUser(ctx context.Context, user *model.User, remote remote.Remote) {
repos, err := remote.GetRepos(user)
if err != nil {
log.Println("Error syncing user account, listing repositories", user.Login, err)
return
}
// insert all repositories
for _, repo := range repos {
var role = repo.Role
if err := datastore.PostRepo(ctx, repo); err != nil {
// typically we see a failure because the repository already exists
// in which case, we can retrieve the existing record to get the ID.
repo, err = datastore.GetRepoName(ctx, repo.Host, repo.Owner, repo.Name)
if err != nil {
log.Println("Error adding repo.", user.Login, repo.Name, err)
continue
}
}
// add user permissions
perm := model.Perm{
UserID: user.ID,
RepoID: repo.ID,
Read: role.Read,
Write: role.Write,
Admin: role.Admin,
}
if err := datastore.PostPerm(ctx, &perm); err != nil {
log.Println("Error adding permissions.", user.Login, repo.Name, err)
continue
}
log.Println("Successfully syced repo.", user.Login+"/"+repo.Name)
}
user.Synced = time.Now().UTC().Unix()
user.Syncing = false
if err := datastore.PutUser(ctx, user); err != nil {
log.Println("Error syncing user account, updating sync date", user.Login, err)
return
}
}