refactored AvatarService

This commit is contained in:
alecmerdler 2017-03-06 00:02:57 -08:00
parent 7b35c0c0d5
commit ff6673fb07
8 changed files with 177 additions and 55 deletions

View file

@ -1,49 +0,0 @@
/**
* Service which provides helper methods for retrieving the avatars displayed in the app.
*/
angular.module('quay').factory('AvatarService', ['Config', '$sanitize', 'md5',
function(Config, $sanitize, md5) {
var avatarService = {};
var cache = {};
avatarService.getAvatar = function(hash, opt_size, opt_notfound) {
var size = opt_size || 16;
switch (Config['AVATAR_KIND']) {
case 'local':
return '/avatar/' + hash + '?size=' + size;
break;
case 'gravatar':
var notfound = opt_notfound || '404';
return '//www.gravatar.com/avatar/' + hash + '?d=' + notfound + '&size=' + size;
break;
}
};
avatarService.computeHash = function(opt_email, opt_name) {
var email = opt_email || '';
var name = opt_name || '';
var cacheKey = email + ':' + name;
if (!cacheKey) { return '-'; }
if (cache[cacheKey]) {
return cache[cacheKey];
}
var hash = md5.createHash(email.toString().toLowerCase());
switch (Config['AVATAR_KIND']) {
case 'local':
if (name) {
hash = name[0] + hash;
} else if (email) {
hash = email[0] + hash;
}
break;
}
return cache[cacheKey] = hash;
};
return avatarService;
}]);

View file

@ -0,0 +1,97 @@
import { AvatarServiceImpl } from './avatar.service.impl';
describe("AvatarServiceImpl", () => {
var avatarServiceImpl: AvatarServiceImpl;
var configMock: any;
var md5Mock: any;
beforeEach(() => {
configMock = {AVATAR_KIND: 'local'};
md5Mock = jasmine.createSpyObj('md5Mock', ['createHash']);
avatarServiceImpl = new AvatarServiceImpl(configMock, md5Mock);
});
describe("getAvatar", () => {
var hash: string;
beforeEach(() => {
hash = "a1b2c3d4e5f6";
});
it("returns a local avatar URL if given config has avatar kind set to local", () => {
var avatarURL: string = avatarServiceImpl.getAvatar(hash);
expect(avatarURL).toEqual(`/avatar/${hash}?size=16`);
});
it("returns a Gravatar URL if given config has avatar kind set to Gravatar", () => {
configMock['AVATAR_KIND'] = 'gravatar';
var avatarURL: string = avatarServiceImpl.getAvatar(hash);
expect(avatarURL).toEqual(`//www.gravatar.com/avatar/${hash}?d=404&size=16`);
});
it("uses 16 as default size query parameter if not provided", () => {
var size: number = 16;
var avatarURL: string = avatarServiceImpl.getAvatar(hash);
expect(avatarURL).toEqual(`/avatar/${hash}?size=${size}`);
});
it("uses 404 as default not found query parameter for Gravatar URL if not provided", () => {
configMock['AVATAR_KIND'] = 'gravatar';
var notFound: string = '404';
var avatarURL: string = avatarServiceImpl.getAvatar(hash);
expect(avatarURL).toEqual(`//www.gravatar.com/avatar/${hash}?d=${notFound}&size=16`);
});
});
describe("computeHash", () => {
var email: string;
var name: string;
var expectedHash: string;
beforeEach(() => {
email = "some_example@gmail.com";
name = "example";
expectedHash = "a1b2c3d4e5f6";
md5Mock.createHash = jasmine.createSpy('createHashSpy').and.returnValue(expectedHash);
});
it("returns hash from cache if it exists", () => {
// Call once to set the cache
avatarServiceImpl.computeHash(email, name);
md5Mock.createHash.calls.reset();
avatarServiceImpl.computeHash(email, name);
expect(md5Mock.createHash).not.toHaveBeenCalled();
});
it("calls MD5 service to create hash using given email if cache is not set", () => {
avatarServiceImpl.computeHash(email, name);
expect(md5Mock.createHash.calls.argsFor(0)[0]).toEqual(email.toString().toLowerCase());
});
it("adds first character of given name to hash if config has avatar kind set to local", () => {
var hash: string = avatarServiceImpl.computeHash(email, name);
expect(hash[0]).toEqual(name[0]);
});
it("adds first character of given email to hash if config has avatar kind set to local and not given name", () => {
var hash: string = avatarServiceImpl.computeHash(email);
expect(hash[0]).toEqual(email[0]);
});
it("adds nothing to hash if config avatar kind is not set to local", () => {
configMock['AVATAR_KIND'] = 'gravatar';
var hash: string = avatarServiceImpl.computeHash(email);
expect(hash).toEqual(expectedHash);
});
});
});

View file

@ -0,0 +1,49 @@
import { AvatarService } from './avatar.service';
import { Injectable } from 'angular-ts-decorators';
@Injectable(AvatarService.name)
export class AvatarServiceImpl implements AvatarService {
private cache: {[cacheKey: string]: string} = {};
constructor(private Config: any, private md5: any) {
}
public getAvatar(hash: string, size: number = 16, notFound: string = '404'): string {
var avatarURL: string;
switch (this.Config['AVATAR_KIND']) {
case 'local':
avatarURL = `/avatar/${hash}?size=${size}`;
break;
case 'gravatar':
avatarURL = `//www.gravatar.com/avatar/${hash}?d=${notFound}&size=${size}`;
break;
}
return avatarURL;
}
public computeHash(email: string = '', name: string = ''): string {
const cacheKey: string = email + ':' + name;
if (this.cache[cacheKey]) {
return this.cache[cacheKey];
}
var hash: string = this.md5.createHash(email.toString().toLowerCase());
switch (this.Config['AVATAR_KIND']) {
case 'local':
if (name) {
hash = name[0] + hash;
} else if (email) {
hash = email[0] + hash;
}
break;
}
return this.cache[cacheKey] = hash;
}
}

View file

@ -0,0 +1,22 @@
/**
* Service which provides helper methods for retrieving the avatars displayed in the app.
*/
export abstract class AvatarService {
/**
* Retrieve URL for avatar image with given hash.
* @param hash Avatar image hash.
* @param size Avatar image size.
* @param notFound URL parameter if avatar image is not found.
* @return avatarURL The URL for the avatar image.
*/
public abstract getAvatar(hash: string, size?: number, notFound?: string): string;
/**
* Compute the avatar image hash.
* @param email Email for avatar user.
* @param name Username for avatar user.
* @return hash The hash for the avatar image.
*/
public abstract computeHash(email?: string, name?: string): string;
}

View file

@ -9,14 +9,14 @@ describe("Service: PageServiceImpl", () => {
});
describe("create", () => {
// TODO
});
describe("get", () => {
// TODO
});
describe("$get", () => {
// TODO
});
});