2014-08-12 22:32:18 -04:00
|
|
|
/*
|
|
|
|
Copyright 2014 matrix.org
|
|
|
|
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
you may not use this file except in compliance with the License.
|
|
|
|
You may obtain a copy of the License at
|
|
|
|
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
See the License for the specific language governing permissions and
|
|
|
|
limitations under the License.
|
|
|
|
*/
|
|
|
|
|
2014-08-12 10:10:52 -04:00
|
|
|
'use strict';
|
|
|
|
|
2014-08-15 09:06:48 -04:00
|
|
|
/*
|
|
|
|
This service wraps up Matrix API calls.
|
|
|
|
|
|
|
|
This serves to isolate the caller from changes to the underlying url paths, as
|
|
|
|
well as attach common params (e.g. access_token) to requests.
|
|
|
|
*/
|
2014-08-12 10:10:52 -04:00
|
|
|
angular.module('matrixService', [])
|
2014-08-14 08:59:33 -04:00
|
|
|
.factory('matrixService', ['$http', '$q', '$rootScope', function($http, $q, $rootScope) {
|
2014-08-12 10:10:52 -04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Permanent storage of user information
|
|
|
|
* The config contains:
|
|
|
|
* - homeserver url
|
|
|
|
* - Identity server url
|
|
|
|
* - user_id
|
|
|
|
* - access_token
|
|
|
|
* - version: the version of this cache
|
|
|
|
*/
|
|
|
|
var config;
|
|
|
|
|
|
|
|
// Current version of permanent storage
|
|
|
|
var configVersion = 0;
|
|
|
|
var prefixPath = "/matrix/client/api/v1";
|
|
|
|
var MAPPING_PREFIX = "alias_for_";
|
|
|
|
|
|
|
|
var doRequest = function(method, path, params, data) {
|
2014-08-15 09:06:48 -04:00
|
|
|
if (!config) {
|
|
|
|
console.warn("No config exists. Cannot perform request to "+path);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-08-12 10:10:52 -04:00
|
|
|
// Inject the access token
|
|
|
|
if (!params) {
|
|
|
|
params = {};
|
|
|
|
}
|
2014-08-15 09:06:48 -04:00
|
|
|
|
2014-08-12 10:10:52 -04:00
|
|
|
params.access_token = config.access_token;
|
|
|
|
|
2014-08-18 10:50:55 -04:00
|
|
|
if (path.indexOf(prefixPath) !== 0) {
|
|
|
|
path = prefixPath + path;
|
|
|
|
}
|
|
|
|
|
2014-08-12 10:10:52 -04:00
|
|
|
return doBaseRequest(config.homeserver, method, path, params, data, undefined);
|
|
|
|
};
|
|
|
|
|
|
|
|
var doBaseRequest = function(baseUrl, method, path, params, data, headers) {
|
2014-08-14 10:36:40 -04:00
|
|
|
return $http({
|
2014-08-12 10:10:52 -04:00
|
|
|
method: method,
|
|
|
|
url: baseUrl + path,
|
|
|
|
params: params,
|
|
|
|
data: data,
|
|
|
|
headers: headers
|
|
|
|
})
|
|
|
|
|
|
|
|
return deferred.promise;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
/****** Home server API ******/
|
|
|
|
prefix: prefixPath,
|
|
|
|
|
|
|
|
// Register an user
|
|
|
|
register: function(user_name, password) {
|
|
|
|
// The REST path spec
|
|
|
|
var path = "/register";
|
|
|
|
|
|
|
|
return doRequest("POST", path, undefined, {
|
|
|
|
user_id: user_name,
|
|
|
|
password: password
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
|
|
|
// Create a room
|
|
|
|
create: function(room_id, visibility) {
|
|
|
|
// The REST path spec
|
|
|
|
var path = "/rooms";
|
|
|
|
|
|
|
|
return doRequest("POST", path, undefined, {
|
|
|
|
visibility: visibility,
|
|
|
|
room_alias_name: room_id
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
|
|
|
// List all rooms joined or been invited to
|
|
|
|
rooms: function(from, to, limit) {
|
|
|
|
// The REST path spec
|
|
|
|
var path = "/im/sync";
|
|
|
|
|
|
|
|
return doRequest("GET", path);
|
|
|
|
},
|
|
|
|
|
|
|
|
// Joins a room
|
|
|
|
join: function(room_id) {
|
|
|
|
// The REST path spec
|
|
|
|
var path = "/rooms/$room_id/members/$user_id/state";
|
|
|
|
|
|
|
|
// Like the cmd client, escape room ids
|
|
|
|
room_id = encodeURIComponent(room_id);
|
|
|
|
|
|
|
|
// Customize it
|
|
|
|
path = path.replace("$room_id", room_id);
|
|
|
|
path = path.replace("$user_id", config.user_id);
|
|
|
|
|
|
|
|
return doRequest("PUT", path, undefined, {
|
|
|
|
membership: "join"
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
2014-08-12 12:17:10 -04:00
|
|
|
joinAlias: function(room_alias) {
|
|
|
|
var path = "/join/$room_alias";
|
|
|
|
room_alias = encodeURIComponent(room_alias);
|
|
|
|
|
|
|
|
path = path.replace("$room_alias", room_alias);
|
|
|
|
|
|
|
|
return doRequest("PUT", path, undefined, {});
|
|
|
|
},
|
|
|
|
|
2014-08-12 10:10:52 -04:00
|
|
|
// Invite a user to a room
|
|
|
|
invite: function(room_id, user_id) {
|
|
|
|
// The REST path spec
|
|
|
|
var path = "/rooms/$room_id/members/$user_id/state";
|
|
|
|
|
|
|
|
// Like the cmd client, escape room ids
|
|
|
|
room_id = encodeURIComponent(room_id);
|
|
|
|
|
|
|
|
// Customize it
|
|
|
|
path = path.replace("$room_id", room_id);
|
|
|
|
path = path.replace("$user_id", user_id);
|
|
|
|
|
|
|
|
return doRequest("PUT", path, undefined, {
|
|
|
|
membership: "invite"
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
|
|
|
// Leaves a room
|
|
|
|
leave: function(room_id) {
|
|
|
|
// The REST path spec
|
|
|
|
var path = "/rooms/$room_id/members/$user_id/state";
|
|
|
|
|
|
|
|
// Like the cmd client, escape room ids
|
|
|
|
room_id = encodeURIComponent(room_id);
|
|
|
|
|
|
|
|
// Customize it
|
|
|
|
path = path.replace("$room_id", room_id);
|
|
|
|
path = path.replace("$user_id", config.user_id);
|
|
|
|
|
|
|
|
return doRequest("DELETE", path, undefined, undefined);
|
|
|
|
},
|
|
|
|
|
2014-08-18 11:11:08 -04:00
|
|
|
// Retrieves the room ID corresponding to a room alias
|
|
|
|
resolveRoomAlias:function(room_alias) {
|
|
|
|
var path = "/matrix/client/api/v1/ds/room/$room_alias";
|
|
|
|
room_alias = encodeURIComponent(room_alias);
|
|
|
|
|
|
|
|
path = path.replace("$room_alias", room_alias);
|
|
|
|
|
|
|
|
return doRequest("GET", path, undefined, {});
|
|
|
|
},
|
|
|
|
|
2014-08-12 10:10:52 -04:00
|
|
|
sendMessage: function(room_id, msg_id, content) {
|
|
|
|
// The REST path spec
|
|
|
|
var path = "/rooms/$room_id/messages/$from/$msg_id";
|
|
|
|
|
|
|
|
if (!msg_id) {
|
|
|
|
msg_id = "m" + new Date().getTime();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Like the cmd client, escape room ids
|
|
|
|
room_id = encodeURIComponent(room_id);
|
|
|
|
|
|
|
|
// Customize it
|
|
|
|
path = path.replace("$room_id", room_id);
|
|
|
|
path = path.replace("$from", config.user_id);
|
|
|
|
path = path.replace("$msg_id", msg_id);
|
|
|
|
|
|
|
|
return doRequest("PUT", path, undefined, content);
|
|
|
|
},
|
|
|
|
|
|
|
|
// Send a text message
|
|
|
|
sendTextMessage: function(room_id, body, msg_id) {
|
|
|
|
var content = {
|
|
|
|
msgtype: "m.text",
|
|
|
|
body: body
|
|
|
|
};
|
|
|
|
|
|
|
|
return this.sendMessage(room_id, msg_id, content);
|
|
|
|
},
|
|
|
|
|
2014-08-13 05:42:28 -04:00
|
|
|
// Send an image message
|
|
|
|
sendImageMessage: function(room_id, image_url, image_alt, msg_id) {
|
|
|
|
var content = {
|
|
|
|
msgtype: "m.image",
|
|
|
|
url: image_url,
|
|
|
|
body: image_alt
|
|
|
|
};
|
|
|
|
|
|
|
|
return this.sendMessage(room_id, msg_id, content);
|
|
|
|
},
|
|
|
|
|
2014-08-12 10:10:52 -04:00
|
|
|
// Send an emote message
|
|
|
|
sendEmoteMessage: function(room_id, body, msg_id) {
|
|
|
|
var content = {
|
|
|
|
msgtype: "m.emote",
|
|
|
|
body: body
|
|
|
|
};
|
|
|
|
|
|
|
|
return this.sendMessage(room_id, msg_id, content);
|
|
|
|
},
|
|
|
|
|
|
|
|
// get a snapshot of the members in a room.
|
|
|
|
getMemberList: function(room_id) {
|
|
|
|
// Like the cmd client, escape room ids
|
|
|
|
room_id = encodeURIComponent(room_id);
|
|
|
|
|
|
|
|
var path = "/rooms/$room_id/members/list";
|
|
|
|
path = path.replace("$room_id", room_id);
|
|
|
|
return doRequest("GET", path);
|
|
|
|
},
|
2014-08-14 12:23:47 -04:00
|
|
|
|
|
|
|
paginateBackMessages: function(room_id, from_token, limit) {
|
|
|
|
var path = "/rooms/$room_id/messages/list";
|
|
|
|
path = path.replace("$room_id", room_id);
|
|
|
|
var params = {
|
|
|
|
from: from_token,
|
|
|
|
to: "START",
|
|
|
|
limit: limit
|
|
|
|
};
|
|
|
|
return doRequest("GET", path, params);
|
|
|
|
},
|
2014-08-12 10:10:52 -04:00
|
|
|
|
|
|
|
// get a list of public rooms on your home server
|
|
|
|
publicRooms: function() {
|
|
|
|
var path = "/public/rooms"
|
|
|
|
return doRequest("GET", path);
|
|
|
|
},
|
|
|
|
|
|
|
|
// get a display name for this user ID
|
|
|
|
getDisplayName: function(userId) {
|
|
|
|
return this.getProfileInfo(userId, "displayname");
|
|
|
|
},
|
|
|
|
|
|
|
|
// get the profile picture url for this user ID
|
|
|
|
getProfilePictureUrl: function(userId) {
|
|
|
|
return this.getProfileInfo(userId, "avatar_url");
|
|
|
|
},
|
|
|
|
|
|
|
|
// update your display name
|
|
|
|
setDisplayName: function(newName) {
|
|
|
|
var content = {
|
|
|
|
displayname: newName
|
|
|
|
};
|
|
|
|
return this.setProfileInfo(content, "displayname");
|
|
|
|
},
|
|
|
|
|
|
|
|
// update your profile picture url
|
|
|
|
setProfilePictureUrl: function(newUrl) {
|
|
|
|
var content = {
|
|
|
|
avatar_url: newUrl
|
|
|
|
};
|
|
|
|
return this.setProfileInfo(content, "avatar_url");
|
|
|
|
},
|
|
|
|
|
|
|
|
setProfileInfo: function(data, info_segment) {
|
|
|
|
var path = "/profile/$user/" + info_segment;
|
|
|
|
path = path.replace("$user", config.user_id);
|
|
|
|
return doRequest("PUT", path, undefined, data);
|
|
|
|
},
|
|
|
|
|
|
|
|
getProfileInfo: function(userId, info_segment) {
|
|
|
|
var path = "/profile/$user_id/" + info_segment;
|
|
|
|
path = path.replace("$user_id", userId);
|
|
|
|
return doRequest("GET", path);
|
|
|
|
},
|
|
|
|
|
|
|
|
login: function(userId, password) {
|
|
|
|
// TODO We should be checking to make sure the client can support
|
|
|
|
// logging in to this HS, else use the fallback.
|
|
|
|
var path = "/login";
|
|
|
|
var data = {
|
|
|
|
"type": "m.login.password",
|
|
|
|
"user": userId,
|
|
|
|
"password": password
|
|
|
|
};
|
|
|
|
return doRequest("POST", path, undefined, data);
|
|
|
|
},
|
|
|
|
|
|
|
|
// hit the Identity Server for a 3PID request.
|
|
|
|
linkEmail: function(email) {
|
|
|
|
var path = "/matrix/identity/api/v1/validate/email/requestToken"
|
|
|
|
var data = "clientSecret=abc123&email=" + encodeURIComponent(email);
|
|
|
|
var headers = {};
|
|
|
|
headers["Content-Type"] = "application/x-www-form-urlencoded";
|
|
|
|
return doBaseRequest(config.identityServer, "POST", path, {}, data, headers);
|
|
|
|
},
|
|
|
|
|
|
|
|
authEmail: function(userId, tokenId, code) {
|
|
|
|
var path = "/matrix/identity/api/v1/validate/email/submitToken";
|
|
|
|
var data = "token="+code+"&mxId="+encodeURIComponent(userId)+"&tokenId="+tokenId;
|
|
|
|
var headers = {};
|
|
|
|
headers["Content-Type"] = "application/x-www-form-urlencoded";
|
|
|
|
return doBaseRequest(config.identityServer, "POST", path, {}, data, headers);
|
|
|
|
},
|
|
|
|
|
2014-08-18 10:50:55 -04:00
|
|
|
uploadContent: function(file) {
|
|
|
|
var path = "/matrix/content";
|
|
|
|
var headers = {
|
|
|
|
"Content-Type": undefined // undefined means angular will figure it out
|
|
|
|
};
|
|
|
|
var params = {
|
|
|
|
access_token: config.access_token
|
|
|
|
};
|
|
|
|
return doBaseRequest(config.homeserver, "POST", path, params, file, headers);
|
|
|
|
},
|
|
|
|
|
2014-08-15 05:20:14 -04:00
|
|
|
// start listening on /events
|
|
|
|
getEventStream: function(from, timeout) {
|
|
|
|
var path = "/events";
|
|
|
|
var params = {
|
|
|
|
from: from,
|
|
|
|
timeout: timeout
|
|
|
|
};
|
|
|
|
return doRequest("GET", path, params);
|
|
|
|
},
|
2014-08-18 04:44:29 -04:00
|
|
|
|
|
|
|
// Indicates if user authentications details are stored in cache
|
|
|
|
isUserLoggedIn: function() {
|
|
|
|
var config = this.config();
|
|
|
|
|
|
|
|
// User is considered logged in if his cache is not empty and contains
|
|
|
|
// an access token
|
|
|
|
if (config && config.access_token) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return false;
|
|
|
|
}
|
2014-08-14 08:59:33 -04:00
|
|
|
},
|
2014-08-18 04:44:29 -04:00
|
|
|
|
2014-08-12 10:10:52 -04:00
|
|
|
/****** Permanent storage of user information ******/
|
|
|
|
|
|
|
|
// Returns the current config
|
|
|
|
config: function() {
|
|
|
|
if (!config) {
|
|
|
|
config = localStorage.getItem("config");
|
|
|
|
if (config) {
|
|
|
|
config = JSON.parse(config);
|
|
|
|
|
|
|
|
// Reset the cache if the version loaded is not the expected one
|
|
|
|
if (configVersion !== config.version) {
|
|
|
|
config = undefined;
|
|
|
|
this.saveConfig();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return config;
|
|
|
|
},
|
|
|
|
|
|
|
|
// Set a new config (Use saveConfig to actually store it permanently)
|
|
|
|
setConfig: function(newConfig) {
|
|
|
|
config = newConfig;
|
|
|
|
},
|
|
|
|
|
|
|
|
// Commits config into permanent storage
|
|
|
|
saveConfig: function() {
|
|
|
|
config.version = configVersion;
|
|
|
|
localStorage.setItem("config", JSON.stringify(config));
|
|
|
|
},
|
|
|
|
|
|
|
|
createRoomIdToAliasMapping: function(roomId, alias) {
|
|
|
|
localStorage.setItem(MAPPING_PREFIX+roomId, alias);
|
|
|
|
},
|
|
|
|
|
|
|
|
getRoomIdToAliasMapping: function(roomId) {
|
|
|
|
return localStorage.getItem(MAPPING_PREFIX+roomId);
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
}]);
|