forked-synapse/webclient/components/matrix/matrix-service.js

333 lines
11 KiB
JavaScript

/*
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.
*/
'use strict';
angular.module('matrixService', [])
.factory('matrixService', ['$http', '$q', function($http, $q) {
/*
* 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) {
// Inject the access token
if (!params) {
params = {};
}
params.access_token = config.access_token;
return doBaseRequest(config.homeserver, method, path, params, data, undefined);
};
var doBaseRequest = function(baseUrl, method, path, params, data, headers) {
if (path.indexOf(prefixPath) !== 0) {
path = prefixPath + path;
}
// Do not directly return the $http instance but return a promise
// with enriched or cleaned information
var deferred = $q.defer();
$http({
method: method,
url: baseUrl + path,
params: params,
data: data,
headers: headers
})
.success(function(data, status, headers, config) {
// @TODO: We could detect a bad access token here and make an automatic logout
deferred.resolve(data, status, headers, config);
})
.error(function(data, status, headers, config) {
// Enrich the error callback with an human readable error reason
var reason = data.error;
if (!data.error) {
reason = JSON.stringify(data);
}
deferred.reject(reason, data, status, headers, config);
});
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"
});
},
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, {});
},
// 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);
},
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);
},
// 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);
},
// 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);
},
/****** 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);
}
};
}]);