PLT-1586 adding attach device id method

Этот коммит содержится в:
=Corey Hulen
2016-01-26 20:32:24 -05:00
родитель 21d51f8c90
Коммит c2bc9454ce
9 изменённых файлов: 145 добавлений и 11 удалений

Просмотреть файл

@@ -48,6 +48,7 @@ func InitUser(r *mux.Router) {
sr.Handle("/logout", ApiUserRequired(logout)).Methods("POST") sr.Handle("/logout", ApiUserRequired(logout)).Methods("POST")
sr.Handle("/login_ldap", ApiAppHandler(loginLdap)).Methods("POST") sr.Handle("/login_ldap", ApiAppHandler(loginLdap)).Methods("POST")
sr.Handle("/revoke_session", ApiUserRequired(revokeSession)).Methods("POST") sr.Handle("/revoke_session", ApiUserRequired(revokeSession)).Methods("POST")
sr.Handle("/attach_device", ApiUserRequired(attachDeviceId)).Methods("POST")
sr.Handle("/switch_to_sso", ApiAppHandler(switchToSSO)).Methods("POST") sr.Handle("/switch_to_sso", ApiAppHandler(switchToSSO)).Methods("POST")
sr.Handle("/switch_to_email", ApiUserRequired(switchToEmail)).Methods("POST") sr.Handle("/switch_to_email", ApiUserRequired(switchToEmail)).Methods("POST")
@@ -546,7 +547,6 @@ func Login(c *Context, w http.ResponseWriter, r *http.Request, user *model.User,
} }
} }
} }
} else { } else {
session.SetExpireInDays(*utils.Cfg.ServiceSettings.SessionLengthWebInDays) session.SetExpireInDays(*utils.Cfg.ServiceSettings.SessionLengthWebInDays)
} }
@@ -718,6 +718,49 @@ func revokeSession(c *Context, w http.ResponseWriter, r *http.Request) {
w.Write([]byte(model.MapToJson(props))) w.Write([]byte(model.MapToJson(props)))
} }
func attachDeviceId(c *Context, w http.ResponseWriter, r *http.Request) {
props := model.MapFromJson(r.Body)
deviceId := props["device_id"]
if len(deviceId) == 0 {
c.SetInvalidParam("attachDevice", "deviceId")
return
}
if !(strings.HasPrefix(deviceId, model.PUSH_NOTIFY_APPLE+":") || strings.HasPrefix(deviceId, model.PUSH_NOTIFY_ANDROID+":")) {
c.SetInvalidParam("attachDevice", "deviceId")
return
}
// A special case where we logout of all other sessions with the same Id
if result := <-Srv.Store.Session().GetSessions(c.Session.UserId); result.Err != nil {
c.Err = result.Err
c.Err.StatusCode = http.StatusForbidden
return
} else {
sessions := result.Data.([]*model.Session)
for _, session := range sessions {
if session.DeviceId == deviceId && session.Id != c.Session.Id {
l4g.Debug(utils.T("api.user.login.revoking.app_error"), session.Id, c.Session.UserId)
RevokeSessionById(c, session.Id)
if c.Err != nil {
c.LogError(c.Err)
c.Err = nil
}
}
}
}
sessionCache.Remove(c.Session.Token)
if result := <-Srv.Store.Session().UpdateDeviceId(c.Session.Id, deviceId); result.Err != nil {
c.Err = result.Err
return
}
w.Write([]byte(deviceId))
}
func RevokeSessionById(c *Context, sessionId string) { func RevokeSessionById(c *Context, sessionId string) {
if result := <-Srv.Store.Session().Get(sessionId); result.Err != nil { if result := <-Srv.Store.Session().Get(sessionId); result.Err != nil {
c.Err = result.Err c.Err = result.Err

Просмотреть файл

@@ -734,6 +734,34 @@ func TestUserUpdateRoles(t *testing.T) {
} }
} }
func TestUserUpdateDeviceId(t *testing.T) {
Setup()
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user := &model.User{TeamId: team.Id, Email: "test@nowhere.com", Nickname: "Corey Hulen", Password: "pwd"}
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user.Id))
Client.LoginByEmail(team.Name, user.Email, "pwd")
deviceId := model.PUSH_NOTIFY_APPLE + ":1234567890"
if _, err := Client.AttachDeviceId(deviceId); err != nil {
t.Fatal(err)
}
if result := <-Srv.Store.Session().GetSessions(user.Id); result.Err != nil {
t.Fatal(result.Err)
} else {
sessions := result.Data.([]*model.Session)
if sessions[0].DeviceId != deviceId {
t.Fatal("Missing device Id")
}
}
}
func TestUserUpdateActive(t *testing.T) { func TestUserUpdateActive(t *testing.T) {
Setup() Setup()

Просмотреть файл

@@ -2771,6 +2771,10 @@
"id": "store.sql_session.update_roles.app_error", "id": "store.sql_session.update_roles.app_error",
"translation": "We couldn't update the roles" "translation": "We couldn't update the roles"
}, },
{
"id": "store.sql_session.update_device_id.app_error",
"translation": "We couldn't update the device id"
},
{ {
"id": "store.sql_system.get.app_error", "id": "store.sql_system.get.app_error",
"translation": "We encountered an error finding the system properties" "translation": "We encountered an error finding the system properties"

Просмотреть файл

@@ -775,6 +775,17 @@ func (c *Client) UpdateUserRoles(data map[string]string) (*Result, *AppError) {
} }
} }
func (c *Client) AttachDeviceId(deviceId string) (*Result, *AppError) {
data := make(map[string]string)
data["device_id"] = deviceId
if r, err := c.DoApiPost("/users/attach_device", MapToJson(data)); err != nil {
return nil, err
} else {
return &Result{r.Header.Get(HEADER_REQUEST_ID),
r.Header.Get(HEADER_ETAG_SERVER), UserFromJson(r.Body)}, nil
}
}
func (c *Client) UpdateActive(userId string, active bool) (*Result, *AppError) { func (c *Client) UpdateActive(userId string, active bool) (*Result, *AppError) {
data := make(map[string]string) data := make(map[string]string)
data["user_id"] = userId data["user_id"] = userId

Просмотреть файл

@@ -28,7 +28,7 @@ var CurrentVersion string = versions[0]
var BuildNumber = "_BUILD_NUMBER_" var BuildNumber = "_BUILD_NUMBER_"
var BuildDate = "_BUILD_DATE_" var BuildDate = "_BUILD_DATE_"
var BuildHash = "_BUILD_HASH_" var BuildHash = "_BUILD_HASH_"
var BuildEnterpriseReady = "_BUILD_ENTERPRISE_READY_" var BuildEnterpriseReady = "false"
func SplitVersion(version string) (int64, int64, int64) { func SplitVersion(version string) (int64, int64, int64) {
parts := strings.Split(version, ".") parts := strings.Split(version, ".")

Просмотреть файл

@@ -232,3 +232,21 @@ func (me SqlSessionStore) UpdateRoles(userId, roles string) StoreChannel {
return storeChannel return storeChannel
} }
func (me SqlSessionStore) UpdateDeviceId(id, deviceId string) StoreChannel {
storeChannel := make(StoreChannel)
go func() {
result := StoreResult{}
if _, err := me.GetMaster().Exec("UPDATE Sessions SET DeviceId = :DeviceId WHERE Id = :Id", map[string]interface{}{"DeviceId": deviceId, "Id": id}); err != nil {
result.Err = model.NewLocAppError("SqlSessionStore.UpdateDeviceId", "store.sql_session.update_device_id.app_error", nil, "")
} else {
result.Data = deviceId
}
storeChannel <- result
close(storeChannel)
}()
return storeChannel
}

Просмотреть файл

@@ -157,6 +157,28 @@ func TestSessionRemoveToken(t *testing.T) {
} }
} }
func TestSessionUpdateDeviceId(t *testing.T) {
Setup()
s1 := model.Session{}
s1.UserId = model.NewId()
s1.TeamId = model.NewId()
Must(store.Session().Save(&s1))
if rs1 := (<-store.Session().UpdateDeviceId(s1.Id, model.PUSH_NOTIFY_APPLE+":1234567890")); rs1.Err != nil {
t.Fatal(rs1.Err)
}
s2 := model.Session{}
s2.UserId = model.NewId()
s2.TeamId = model.NewId()
Must(store.Session().Save(&s2))
if rs2 := (<-store.Session().UpdateDeviceId(s2.Id, model.PUSH_NOTIFY_APPLE+":1234567890")); rs2.Err != nil {
t.Fatal(rs2.Err)
}
}
func TestSessionStoreUpdateLastActivityAt(t *testing.T) { func TestSessionStoreUpdateLastActivityAt(t *testing.T) {
Setup() Setup()

Просмотреть файл

@@ -137,6 +137,7 @@ type SessionStore interface {
PermanentDeleteSessionsByUser(teamId string) StoreChannel PermanentDeleteSessionsByUser(teamId string) StoreChannel
UpdateLastActivityAt(sessionId string, time int64) StoreChannel UpdateLastActivityAt(sessionId string, time int64) StoreChannel
UpdateRoles(userId string, roles string) StoreChannel UpdateRoles(userId string, roles string) StoreChannel
UpdateDeviceId(sessionIdOrToken string, deviceId string) StoreChannel
} }
type AuditStore interface { type AuditStore interface {

Просмотреть файл

@@ -137,6 +137,21 @@ export default class Login extends React.Component {
); );
} }
let findTeams = null;
if (!Utils.isMobileApp()) {
findTeams = (
<div className='form-group margin--extra form-group--small'>
<span>
<a href='/find_team'>
<FormattedMessage
id='login.find_teams'
defaultMessage='Find your other teams'
/>
</a></span>
</div>
);
}
return ( return (
<div className='signup-team__container'> <div className='signup-team__container'>
<h5 className='margin--less'>{'Sign in to:'}</h5> <h5 className='margin--less'>{'Sign in to:'}</h5>
@@ -147,15 +162,7 @@ export default class Login extends React.Component {
{emailSignup} {emailSignup}
{ldapLogin} {ldapLogin}
{userSignUp} {userSignUp}
<div className='form-group margin--extra form-group--small'> {findTeams}
<span>
<a href='/find_team'>
<FormattedMessage
id='login.find_teams'
defaultMessage='Find your other teams'
/>
</a></span>
</div>
{forgotPassword} {forgotPassword}
{teamSignUp} {teamSignUp}
</div> </div>