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

317 lines
10 KiB
JavaScript

'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);
}
};
}]);