[New Feature] Add firestore to data layer

This commit is contained in:
Qolzam
2017-11-30 13:41:02 +07:00
parent 92379b615c
commit 22a5b46f36
67 changed files with 1844 additions and 615 deletions

View File

@@ -1,7 +1,4 @@
declare const process: any
import firebase from 'firebase'
try {
let config = {
apiKey: process.env.API_KEY,
@@ -12,7 +9,6 @@ try {
messagingSenderId: process.env.MESSAGING_SENDER_ID
}
console.log(firebase)
firebase.initializeApp(config)
} catch (error) {
console.log('=========Firebase initializer==============')

View File

@@ -1,3 +1,6 @@
import moment from 'moment'
import { Profile } from 'core/domain/users'
// - Import react components
import { firebaseRef, firebaseAuth } from 'data/firebaseClient'
@@ -68,8 +71,8 @@ export class AuthorizeService implements IAuthorizeService {
firebaseAuth()
.createUserWithEmailAndPassword(user.email as string, user.password as string)
.then((signupResult) => {
const {uid, email, displayName, photoURL} = signupResult
this.storeUserInformation(uid,email,displayName,photoURL).then(resolve)
const {uid, email} = signupResult
this.storeUserInformation(uid,email,user.fullName,'').then(resolve)
})
.catch((error: any) => reject(new SocialError(error.code, error.message)))
})
@@ -107,7 +110,7 @@ export class AuthorizeService implements IAuthorizeService {
firebaseAuth().onAuthStateChanged( (user: any) => {
let isVerifide = false
if (user) {
if (user.emailVerified) {
if (user.emailVerified || user.providerData[0].providerId.trim() !== 'password') {
isVerifide = true
} else {
isVerifide = false
@@ -210,15 +213,17 @@ export class AuthorizeService implements IAuthorizeService {
* @private
* @memberof AuthorizeService
*/
private storeUserInformation = (userId: string, email: string, fullName: string, avatar?: string) => {
private storeUserInformation = (userId: string, email: string, fullName: string, avatar: string) => {
return new Promise<RegisterUserResult>((resolve,reject) => {
firebaseRef.child(`users/${userId}/info`)
.set({
userId,
.set(new Profile(
avatar,
email,
fullName
})
fullName,
'',
'',
moment().unix(),
email
))
.then((result) => {
resolve(new RegisterUserResult(userId))
})

View File

@@ -1,5 +1,5 @@
// - Import react components
import { firebaseRef, firebaseAuth } from 'data/firebaseClient'
import { firebaseRef, firebaseAuth, db } from 'data/firebaseClient'
import { SocialError } from 'core/domain/common'
import { ICircleService } from 'core/services/circles'
@@ -18,13 +18,11 @@ export class CircleService implements ICircleService {
public addCircle: (userId: string, circle: Circle)
=> Promise<string> = (userId, circle) => {
return new Promise<string>((resolve,reject) => {
let circleRef = firebaseRef.child(`users/${userId}/circles`).push(circle)
circleRef.then(() => {
resolve(circleRef.key as string)
})
.catch((error: any) => {
reject(new SocialError(error.code, error.message))
})
})

View File

@@ -1,5 +1,6 @@
// - Import react components
import { firebaseRef, firebaseAuth } from 'data/firebaseClient'
import moment from 'moment'
import { SocialError } from 'core/domain/common'
import { Profile, UserProvider } from 'core/domain/users'
@@ -13,6 +14,7 @@ import { IUserService } from 'core/services/users'
* @implements {IUserService}
*/
export class UserService implements IUserService {
public getUserProfile: (userId: string)
=> Promise<Profile> = (userId) => {
return new Promise<Profile>((resolve, reject) => {
@@ -23,7 +25,7 @@ export class UserService implements IUserService {
if (Object.keys(userProfile).length === 0 && userProfile.constructor === Object) {
this.getUserProviderData(userId).then((providerData: UserProvider) => {
const {avatar,fullName, email} = providerData
const userProfile = new Profile(avatar,fullName,'','',email)
const userProfile = new Profile(avatar,fullName,'','', moment().unix(),email)
resolve(userProfile)
this.updateUserProfile(userId,userProfile)
})
@@ -52,10 +54,16 @@ export class UserService implements IUserService {
})
})
}
public getUsersProfile: (userId: string)
=> Promise<{ [userId: string]: Profile }> = (userId) => {
public getUsersProfile: (userId: string, page?: number, lastKey?: string)
=> Promise<{ [userId: string]: Profile }> = (userId, page, lastKey) => {
return new Promise<{ [userId: string]: Profile }>((resolve, reject) => {
let usersProfileRef: any = firebaseRef.child(`users`)
let usersProfileRef: any
if (page) {
const numberOfItems = (page * 12) + 12
usersProfileRef = firebaseRef.child(`users`).orderByKey().startAt(lastKey!).limitToFirst(numberOfItems)
} else {
usersProfileRef = firebaseRef.child(`users`).orderByKey()
}
usersProfileRef.once('value').then((snapshot: any) => {
let usersProfile: any = snapshot.val() || {}

View File

@@ -0,0 +1,31 @@
import firebase from 'firebase'
import 'firebase/firestore'
try {
let config = {
apiKey: process.env.API_KEY,
authDomain: process.env.AUTH_DOMAIN,
databaseURL: process.env.DATABASE_URL,
projectId: process.env.PROJECT_ID,
storageBucket: process.env.STORAGE_BUCKET,
messagingSenderId: process.env.MESSAGING_SENDER_ID
}
firebase.initializeApp(config)
} catch (error) {
console.log('=========Firebase firestore initializer==============')
console.log(error)
console.log('====================================')
}
// - Storage reference
export let storageRef = firebase.storage().ref()
// Initialize Cloud Firestore through Firebase
export const db = firebase.firestore()
// - Database authorize
export let firebaseAuth = firebase.auth
export let firebaseRef = firebase.database().ref()
// - Firebase default
export default firebase

View File

@@ -0,0 +1,264 @@
import { Profile } from 'core/domain/users'
// - Import react components
import { firebaseRef, firebaseAuth, db } from 'data/firestoreClient'
import { IAuthorizeService } from 'core/services/authorize'
import { User, UserProvider } from 'core/domain/users'
import { LoginUser, RegisterUserResult } from 'core/domain/authorize'
import { SocialError } from 'core/domain/common'
import { OAuthType } from 'core/domain/authorize/oauthType'
import moment from 'moment'
/**
* Firbase authorize service
*
* @export
* @class AuthorizeService
* @implements {IAuthorizeService}
*/
export class AuthorizeService implements IAuthorizeService {
/**
* Login the user
*
* @returns {Promise<LoginUser>}
* @memberof IAuthorizeService
*/
public login: (email: string, password: string) => Promise<LoginUser> = (email, password) => {
return new Promise<LoginUser>((resolve, reject) => {
firebaseAuth()
.signInWithEmailAndPassword(email, password)
.then((result) => {
resolve(new LoginUser(result.uid, result.emailVerified))
})
.catch((error: any) => {
reject(new SocialError(error.code, error.message))
})
})
}
/**
* Logs out the user
*
* @returns {Promise<void>}
* @memberof IAuthorizeService
*/
public logout: () => Promise<void> = () => {
return new Promise<void>((resolve, reject) => {
firebaseAuth()
.signOut()
.then((result) => {
resolve()
})
.catch((error: any) => {
reject(new SocialError(error.code, error.message))
})
})
}
/**
* Register a user
*
* @returns {Promise<void>}
* @memberof IAuthorizeService
*/
public registerUser: (user: User) => Promise<RegisterUserResult> = (user) => {
return new Promise<RegisterUserResult>((resolve, reject) => {
firebaseAuth()
.createUserWithEmailAndPassword(user.email as string, user.password as string)
.then((signupResult) => {
const {uid, email} = signupResult
this.storeUserInformation(uid,email,user.fullName,'').then(resolve)
})
.catch((error: any) => reject(new SocialError(error.code, error.message)))
})
}
/**
* Update user password
*
* @returns {Promise<void>}
* @memberof IAuthorizeService
*/
public updatePassword: (newPassword: string) => Promise<void> = (newPassword) => {
return new Promise<void>((resolve, reject) => {
let user = firebaseAuth().currentUser
if (user) {
user.updatePassword(newPassword).then(() => {
// Update successful.
resolve()
}).catch((error: any) => {
// An error happened.
reject(new SocialError(error.code, error.message))
})
}
})
}
/**
* On user authorization changed event
*
* @memberof IAuthorizeService
*/
public onAuthStateChanged: (callBack: (isVerifide: boolean, user: User) => void) => any = (callBack) => {
firebaseAuth().onAuthStateChanged( (user: any) => {
let isVerifide = false
if (user) {
if (user.emailVerified || user.providerData[0].providerId.trim() !== 'password') {
isVerifide = true
} else {
isVerifide = false
}
}
callBack(isVerifide,user)
})
}
/**
* Reset user password
*
* @memberof AuthorizeService
*/
public resetPassword: (email: string) => Promise<void> = (email) => {
return new Promise<void>((resolve,reject) => {
let auth = firebaseAuth()
auth.sendPasswordResetEmail(email).then(function () {
resolve()
}).catch((error: any) => {
// An error happened.
reject(new SocialError(error.code, error.message))
})
})
}
/**
* Send verfication email to user email
*
* @memberof AuthorizeService
*/
public sendEmailVerification: () => Promise<void> = () => {
return new Promise<void>((resolve,reject) => {
let auth = firebaseAuth()
const user = auth.currentUser
if (user) {
user.sendEmailVerification().then(() => {
resolve()
}).catch((error: any) => {
// An error happened.
reject(new SocialError(error.code, error.message))
})
} else {
reject(new SocialError('authorizeService/nullException', 'User was null!'))
}
})
}
public loginWithOAuth: (type: OAuthType) => Promise<LoginUser> = (type) => {
return new Promise<LoginUser>((resolve,reject) => {
let provider: any
switch (type) {
case OAuthType.GITHUB:
provider = new firebaseAuth.GithubAuthProvider()
break
case OAuthType.FACEBOOK:
provider = new firebaseAuth.FacebookAuthProvider()
break
case OAuthType.GOOGLE:
provider = new firebaseAuth.GoogleAuthProvider()
break
default:
throw new SocialError('authorizeService/loginWithOAuth','None of OAuth type is matched!')
}
firebaseAuth().signInWithPopup(provider).then((result) => {
// This gives you a GitHub Access Token. You can use it to access the GitHub API.
let token = result.credential.accessToken
// The signed-in user info.
const {user} = result
const {credential} = result
const {uid, displayName, email, photoURL} = user
const {accessToken, providerId} = credential
this.storeUserProviderData(uid,email,displayName,photoURL,providerId,accessToken)
// this.storeUserInformation(uid,email,displayName,photoURL).then(resolve)
resolve(new LoginUser(user.uid,true,providerId,displayName,email,photoURL))
}).catch(function (error: any) {
// Handle Errors here.
let errorCode = error.code
let errorMessage = error.message
// The email of the user's account used.
let email = error.email
// The firebase.auth.AuthCredential type that was used.
let credential = error.credential
})
})
}
/**
* Store user information
*
* @private
* @memberof AuthorizeService
*/
private storeUserInformation = (userId: string, email: string, fullName: string, avatar: string) => {
return new Promise<RegisterUserResult>((resolve,reject) => {
db.doc(`userInfo/${userId}`).set(
{
avatar,
fullName,
creationDate: moment().unix(),
email
}
)
.then(() => {
alert(userId)
resolve(new RegisterUserResult(userId))
})
.catch((error: any) => reject(new SocialError(error.name, 'firestore/storeUserInformation : ' + error.message)))
})
}
/**
* Store user provider information
*
* @private
* @memberof AuthorizeService
*/
private storeUserProviderData = (
userId: string,
email: string,
fullName: string,
avatar: string,
providerId: string,
accessToken: string
) => {
return new Promise<RegisterUserResult>((resolve,reject) => {
db.doc(`userProviderInfo/${userId}`)
.set(
{
userId,
email,
fullName,
avatar,
providerId,
accessToken
}
)
.then(() => {
resolve(new RegisterUserResult(userId))
})
.catch((error: any) => reject(new SocialError(error.name, error.message)))
})
}
}

View File

@@ -0,0 +1,5 @@
import { AuthorizeService } from './AuthorizeService'
export {
AuthorizeService
}

View File

@@ -0,0 +1,119 @@
// - Import react components
import { firebaseRef, firebaseAuth, db } from 'data/firestoreClient'
import { SocialError } from 'core/domain/common'
import { ICircleService } from 'core/services/circles'
import { Circle, UserFollower } from 'core/domain/circles'
import { User } from 'core/domain/users'
/**
* Firbase circle service
*
* @export
* @class CircleService
* @implements {ICircleService}
*/
export class CircleService implements ICircleService {
public addCircle: (userId: string, circle: Circle)
=> Promise<string> = (userId, circle) => {
return new Promise<string>((resolve,reject) => {
let circleRef = db.doc(`users/${userId}`).collection(`circles`).add(circle)
circleRef.then((result) => {
resolve(result.id as string)
})
})
}
public addFollowingUser: (userId: string, circleId: string, userCircle: User, userFollower: UserFollower, userFollowingId: string)
=> Promise<void> = (userId, circleId, userCircle, userFollower, userFollowingId) => {
return new Promise<void>((resolve,reject) => {
const batch = db.batch()
const followerRef = db.doc(`users/${userId}/circles/${circleId}/users/${userFollowingId}`)
const followingRef = db.doc(`users/${userFollowingId}/circles/-Followers/users/${userId}`)
batch.update(followerRef, userCircle)
batch.update(followingRef, userFollower)
batch.commit().then(() => {
resolve()
})
.catch((error: any) => {
reject(new SocialError(error.code, error.message))
})
})
}
public deleteFollowingUser: (userId: string, circleId: string, userFollowingId: string)
=> Promise<void> = (userId, circleId, userFollowingId) => {
return new Promise<void>((resolve,reject) => {
const batch = db.batch()
const followerRef = db.doc(`users/${userId}/circles/${circleId}/users/${userFollowingId}`)
const followingRef = db.doc(`users/${userFollowingId}/circles/-Followers/users/${userId}`)
batch.delete(followerRef)
batch.delete(followingRef)
batch.commit().then(() => {
resolve()
})
.catch((error: any) => {
reject(new SocialError(error.code, error.message))
})
})
}
public updateCircle: (userId: string, circleId: string, circle: Circle)
=> Promise<void> = (userId, circleId, circle) => {
return new Promise<void>((resolve,reject) => {
const batch = db.batch()
const circleRef = db.doc(`users/${userId}/circles/${circleId}`)
batch.update(circleRef,circle)
batch.commit().then(() => {
resolve()
})
.catch((error: any) => {
reject(new SocialError(error.code, error.message))
})
})
}
public deleteCircle: (userId: string, circleId: string)
=> Promise<void> = (userId, circleId) => {
return new Promise<void>((resolve,reject) => {
const batch = db.batch()
const circleRef = db.doc(`users/${userId}/circles/${circleId}`)
batch.delete(circleRef)
batch.commit().then(() => {
resolve()
})
.catch((error: any) => {
reject(new SocialError(error.code, error.message))
})
})
}
public getCircles: (userId: string) => Promise<{ [circleId: string]: Circle }> = (userId) => {
return new Promise<{ [circleId: string]: Circle }>((resolve,reject) => {
let circlesRef = db.doc(`users/${userId}`).collection(`circles`)
circlesRef.onSnapshot((snapshot) => {
let parsedData: { [circleId: string]: Circle } = {}
snapshot.forEach((result) => {
parsedData[result.id] = {
id: result.id,
...result.data() as Circle
}
})
resolve(parsedData)
})
})
}
}

View File

@@ -0,0 +1,5 @@
import { CircleService } from './CircleService'
export {
CircleService
}

View File

@@ -0,0 +1,133 @@
// - Import react components
import { firebaseRef, firebaseAuth, db } from 'data/firestoreClient'
import _ from 'lodash'
import { SocialError } from 'core/domain/common'
import { ICommentService } from 'core/services/comments'
import { Comment } from 'core/domain/comments'
/**
* Firbase comment service
*
* @export
* @class CommentService
* @implements {ICommentService}
*/
export class CommentService implements ICommentService {
public addComment: (comment: Comment)
=> Promise<string> = (comment) => {
return new Promise<string>((resolve,reject) => {
const postRef = db.doc(`posts/${comment.postId}`)
let commentRef = postRef.collection('comments')
commentRef.add(comment).then((result) => {
resolve(result.id)
/**
* Add comment counter and three comments' slide preview
*/
db.runTransaction((transaction) => {
return transaction.get(postRef).then((postDoc) => {
if (postDoc.exists) {
const commentCount = postDoc.data().commentCounter + 1
transaction.update(postRef, { commentCounter: commentCount })
let comments = postDoc.data()
if (!comments) {
comments = {}
}
if (commentCount < 4) {
transaction.update(postRef, { comments: { ...comments, [result.id]: comment } })
} else {
let sortedObjects = comments
// Sort posts with creation date
sortedObjects.sort((a: any, b: any) => {
return parseInt(b.creationDate,10) - parseInt(a.creationDate,10)
})
const lastCommentId = Object.keys(sortedObjects)[2]
comments[lastCommentId] = {... comment}
transaction.update(postRef, { comments: { ...comments} })
}
}
})
})
})
.catch((error: any) => {
reject(new SocialError(error.code,error.message))
})
})
}
public getComments: (postId: string, callback: (resultComments: { [postId: string]: { [commentId: string]: Comment } }) => void)
=> void = (postId, callback) => {
let commentsRef = db.doc(`posts/${postId}`).collection(`comments`)
commentsRef.onSnapshot((snapshot) => {
let parsedData: {[postId: string]: {[commentId: string]: Comment}} = {[postId]: {}}
snapshot.forEach((result) => {
parsedData[postId][result.id] = {
id: result.id,
...result.data() as Comment
}
})
if (callback) {
callback(parsedData)
}
})
}
public updateComment: (comment: Comment)
=> Promise<void> = (comment) => {
return new Promise<void>((resolve,reject) => {
const batch = db.batch()
const commentRef = db.doc(`posts/${comment.postId}/comments/${comment.id}`)
batch.update(commentRef, comment)
batch.commit().then(() => {
resolve()
})
.catch((error: any) => {
reject(new SocialError(error.code,error.message))
})
})
}
public deleteComment: (commentId: string, postId: string)
=> Promise<void> = (commentId, postId) => {
return new Promise<void>((resolve,reject) => {
const batch = db.batch()
const postRef = db.doc(`posts/${postId}`)
const commentRef = postRef.collection(`comments`).doc(commentId)
batch.delete(commentRef)
batch.commit().then(() => {
resolve()
/**
* Delete comment counter and comments' slide preview
*/
db.runTransaction((transaction) => {
return transaction.get(postRef).then((postDoc) => {
if (postDoc.exists) {
const commentCount = postDoc.data().commentCounter - 1
transaction.update(postRef, { commentCounter: commentCount })
if (commentCount > 3) {
let comments = postDoc.data().comments
if (!comments) {
comments = {}
}
let parsedComments = {}
Object.keys(postDoc.data().comments).map((id) => {
if (id !== commentId) {
_.merge(parsedComments, { [id]: { ...comments[id] } })
}
})
transaction.update(postRef, { comments: { ...parsedComments}})
}
}
})
})
})
.catch((error: any) => {
reject(new SocialError(error.code,error.message))
})
})
}
}

View File

@@ -0,0 +1,5 @@
import { CommentService } from './CommentService'
export {
CommentService
}

View File

@@ -0,0 +1,16 @@
// - Import react components
import { firebaseRef, firebaseAuth } from 'data/firebaseClient'
import { SocialError } from 'core/domain/common'
import { ICommonService } from 'core/services/common'
/**
* Firbase common service
*
* @export
* @class CommonService
* @implements {ICommonService}
*/
export class CommonService implements ICommonService {
}

View File

@@ -0,0 +1,5 @@
import { CommonService } from './CommonService'
export {
CommonService
}

View File

@@ -0,0 +1,41 @@
import { storageRef } from 'data/firestoreClient'
import { IStorageService } from 'core/services/files'
import { FileResult } from 'models/files/fileResult'
export class StorageService implements IStorageService {
/**
* Upload image on the server
* @param {file} file
* @param {string} fileName
*/
public uploadFile = (file: any, fileName: string, progress: (percentage: number, status: boolean) => void) => {
return new Promise<FileResult>((resolve, reject) => {
// Create a storage refrence
let storegeFile = storageRef.child(`images/${fileName}`)
// Upload file
let task = storegeFile.put(file)
task.then((result) => {
resolve(new FileResult(result.downloadURL!,result.metadata.fullPath))
}).catch((error) => {
reject(error)
})
// Upload storage bar
task.on('state_changed', (snapshot: any) => {
let percentage: number = (snapshot.bytesTransferred / snapshot.totalBytes) * 100
progress(percentage, true)
}, (error) => {
console.log('========== Upload Image ============')
console.log(error)
console.log('====================================')
}, () => {
progress(100, false)
})
})
}
}

View File

@@ -0,0 +1,5 @@
import { StorageService } from './StorageService'
export {
StorageService
}

View File

@@ -0,0 +1,111 @@
import { FileResult } from 'models/files/fileResult'
// - Import react components
import { firebaseRef, firebaseAuth, storageRef, db } from 'data/firestoreClient'
import { SocialError } from 'core/domain/common'
import { IImageGalleryService } from 'core/services/imageGallery'
import { Image } from 'core/domain/imageGallery'
import { IStorageService } from 'core/services/files'
import { IServiceProvider, ServiceProvide } from 'core/factories'
/**
* Firbase image gallery service
*
* @export
* @class ImageGalleryService
* @implements {IImageGalleryService}
*/
export class ImageGalleryService implements IImageGalleryService {
private readonly storageService: IStorageService
private readonly serviceProvider: IServiceProvider
constructor () {
this.serviceProvider = new ServiceProvide()
this.storageService = this.serviceProvider.createStorageService()
}
public getImageGallery: (userId: string)
=> Promise<Image[]> = (userId) => {
return new Promise<Image[]>((resolve,reject) => {
let imagesRef = db.doc(`users/${userId}`).collection(`images`)
imagesRef.get().then((snapshot) => {
let parsedData: Image[] = []
snapshot.forEach((result) => {
parsedData.push({
id: result.id,
...result.data() as Image
})
})
resolve(parsedData)
})
.catch((error: any) => {
reject(new SocialError(error.code, error.message))
})
})
}
public saveImage: (userId: string, image: Image)
=> Promise<string> = (userId, image) => {
return new Promise<string>((resolve,reject) => {
let imageRef = db.doc(`users/${userId}`).collection(`images`).add(image)
imageRef.then((result) => {
resolve(result.id!)
})
.catch((error: any) => {
reject(new SocialError(error.code, error.message))
})
})
}
public deleteImage: (userId: string, imageId: string)
=> Promise<void> = (userId, imageId) => {
return new Promise<void>((resolve,reject) => {
const batch = db.batch()
const imageRef = db.doc(`users/${userId}/images/${imageId}`)
batch.delete(imageRef)
batch.commit().then(() => {
resolve()
})
.catch((error: any) => {
reject(new SocialError(error.code, error.message))
})
})
}
public uploadImage: (image: any, imageName: string, progressCallback: (percentage: number, status: boolean) => void)
=> Promise<FileResult> = (image, imageName, progressCallback) => {
return new Promise<FileResult>((resolve,reject) => {
this.storageService.uploadFile(image,imageName,progressCallback)
.then((result: FileResult) => {
resolve(result)
})
.catch((error: any) => {
reject(new SocialError(error.code, error.message))
})
})
}
public downloadImage: (fileName: string)
=> Promise<string> = (fileName) => {
return new Promise<string>((resolve,reject) => {
// Create a reference to the file we want to download
let starsRef: any = storageRef.child(`images/${fileName}`)
// Get the download URL
starsRef.getDownloadURL().then((url: string) => {
resolve(url)
})
.catch((error: any) => {
reject(new SocialError(error.code, error.message))
})
})
}
}

View File

@@ -0,0 +1,5 @@
import { ImageGalleryService } from './ImageGalleryService'
export {
ImageGalleryService
}

View File

@@ -0,0 +1,24 @@
import { AuthorizeService } from './authorize'
import { CircleService } from './circles'
import { CommentService } from './comments'
import { CommonService } from './common'
import { ImageGalleryService } from './imageGallery'
import { NotificationService } from './notifications'
import { PostService } from './posts'
import { UserService } from './users'
import { VoteService } from './votes'
import { StorageService } from './files'
export {
AuthorizeService,
CircleService,
CommentService,
CommonService,
ImageGalleryService,
NotificationService,
PostService,
UserService,
VoteService,
StorageService
}

View File

@@ -0,0 +1,5 @@
import { NotificationService } from './NotificationService'
export {
NotificationService
}

View File

@@ -0,0 +1,74 @@
// - Import react components
import { firebaseRef, firebaseAuth, db } from 'data/firestoreClient'
import { SocialError } from 'core/domain/common'
import { Notification } from 'core/domain/notifications'
import { INotificationService } from 'core/services/notifications'
/**
* Firbase notification service
*
* @export
* @class NotificationService
* @implements {INotificationService}
*/
export class NotificationService implements INotificationService {
public addNotification: (notification: Notification)
=> Promise<void> = (notification: Notification) => {
return new Promise<void>((resolve,reject) => {
db.doc(`users/${notification.notifyRecieverUserId}`).collection(`notifications`)
.add(notification)
.then(() => {
resolve()
})
})
}
public getNotifications: (userId: string, callback: (resultNotifications: {[notifyId: string]: Notification}) => void)
=> void = (userId,callback) => {
let notificationsRef = db.doc(`users/${userId}`).collection('notifications')
notificationsRef.onSnapshot((snapshot) => {
let parsedData: { [notifyId: string]: Notification } = {}
snapshot.forEach((result) => {
parsedData[result.id] = {
id: result.id,
...result.data() as Notification
}
})
callback(parsedData)
})
}
public deleteNotification: (notificationId: string, userId: string)
=> Promise < void > = (notificationId, userId) => {
return new Promise<void>((resolve, reject) => {
const batch = db.batch()
const notificationRef = db.doc(`users/${userId}/notifications/${notificationId}`)
batch.delete(notificationRef)
batch.commit().then(() => {
resolve()
})
.catch((error: any) => {
reject(new SocialError(error.code, error.message))
})
})
}
public setSeenNotification: (notificationId: string, userId: string, notification: Notification)
=> Promise <void> = (notificationId, userId, notification) => {
return new Promise<void>((resolve, reject) => {
const batch = db.batch()
const notificationRef = db.doc(`users/${userId}/notifications/${notificationId}`)
batch.update(notificationRef,notification)
batch.commit().then(() => {
resolve()
})
.catch((error: any) => {
reject(new SocialError(error.code, error.message))
})
})
}
}

View File

@@ -0,0 +1,105 @@
// - Import react components
import { firebaseRef, firebaseAuth, db } from 'data/firestoreClient'
import { SocialError } from 'core/domain/common'
import { Post } from 'core/domain/posts'
import { IPostService } from 'core/services/posts'
import { IServiceProvider } from 'core/factories'
import { ICommentService } from 'core/services/comments'
import { ServiceProvide } from 'core/factories/serviceProvide'
/**
* Firbase post service
*
* @export
* @class PostService
* @implements {IPostService}
*/
export class PostService implements IPostService {
public addPost: (post: Post)
=> Promise<string> = (post) => {
return new Promise<string>((resolve,reject) => {
let postRef = db.collection(`posts`).add(post)
postRef.then((result) => {
resolve(result.id)
})
.catch((error: any) => {
reject(new SocialError(error.code,error.message))
})
})
}
public updatePost: (post: Post)
=> Promise<void> = (post) => {
return new Promise<void>((resolve,reject) => {
const batch = db.batch()
const notificationRef = db.doc(`posts/${post.id}`)
batch.update(notificationRef, post)
batch.commit().then(() => {
resolve()
})
.catch((error: any) => {
reject(new SocialError(error.code,error.message))
})
})
}
public deletePost: (postId: string)
=> Promise<void> = (postId) => {
return new Promise<void>((resolve,reject) => {
const batch = db.batch()
const notificationRef = db.doc(`posts/${postId}`)
batch.delete(notificationRef)
batch.commit().then(() => {
resolve()
})
.catch((error: any) => {
reject(new SocialError(error.code,error.message))
})
})
}
public getPosts: (userId: string)
=> Promise<{ [postId: string]: Post }> = (userId) => {
return new Promise<{ [postId: string]: Post }>((resolve,reject) => {
let postsRef = db.collection(`posts`).where('ownerUserId', '==', userId)
postsRef.get().then((snapshot) => {
let parsedData: { [postId: string]: Post } = {}
snapshot.forEach((result) => {
parsedData[result.id] = {
id: result.id,
...result.data() as Post
}
})
resolve(parsedData)
})
.catch((error: any) => {
reject(new SocialError(error.code,error.message))
})
})
}
public getPostById: (postId: string)
=> Promise<Post> = (postId) => {
return new Promise<Post>((resolve,reject) => {
let postsRef = db.doc(`posts/${postId}`)
postsRef.get().then((snapshot) => {
let newPost = snapshot.data() || {}
let post: Post = {
id: postId,
...newPost
}
resolve(post)
})
.catch((error: any) => {
reject(new SocialError(error.code,error.message))
})
})
}
}

View File

@@ -0,0 +1,5 @@
import { PostService } from './PostService'
export {
PostService
}

View File

@@ -0,0 +1,92 @@
// - Import react components
import { firebaseRef, firebaseAuth, db } from 'data/firestoreClient'
import firebase from 'firebase'
import moment from 'moment'
import { SocialError } from 'core/domain/common'
import { Profile, UserProvider } from 'core/domain/users'
import { IUserService } from 'core/services/users'
/**
* Firbase user service
*
* @export
* @class UserService
* @implements {IUserService}
*/
export class UserService implements IUserService {
public getUserProfile: (userId: string)
=> Promise<Profile> = (userId) => {
return new Promise<Profile>((resolve, reject) => {
let userProfileRef = db.doc(`userInfo/${userId}`)
userProfileRef.get().then((snapshot) => {
if (!snapshot.exists) {
this.getUserProviderData(userId).then((providerData: UserProvider) => {
const {avatar,fullName, email} = providerData
const userProfile = new Profile(avatar,fullName,'','',moment().unix(),email)
resolve(userProfile)
this.updateUserProfile(userId,userProfile)
})
} else {
resolve(snapshot.data() as Profile)
}
})
.catch((error: any) => reject(new SocialError(error.code, 'firestore/getUserProfile :' + error.message)))
})
}
public updateUserProfile: (userId: string, profile: Profile)
=> Promise<void> = (userId, profile) => {
return new Promise<void>((resolve, reject) => {
const batch = db.batch()
const profileRef = db.doc(`userInfo/${userId}`)
batch.set(profileRef,{...profile})
batch.commit().then(() => {
resolve()
})
.catch((error: any) => reject(new SocialError(error.code, 'firestore/updateUserProfile' + error.message)))
})
}
public getUsersProfile: (userId: string, lastKey?: string, numberOfItems?: number)
=> Promise<{ [userId: string]: Profile }> = (userId, lastKey, numberOfItems = 15) => {
return new Promise<{ [userId: string]: Profile }>((resolve, reject) => {
let usersProfileRef: firebase.firestore.Query
if (lastKey) {
usersProfileRef = db.collection(`userInfo`).orderBy('creationDate', 'desc').startAfter(lastKey!).limit(numberOfItems)
} else {
usersProfileRef = db.collection(`userInfo`).orderBy('creationDate', 'desc')
}
usersProfileRef.get().then((snapshot) => {
let parsedData: { [userId: string]: Profile } = {}
snapshot.forEach((result) => {
parsedData[result.id] = {
...result.data() as Profile
}
})
resolve(parsedData)
})
.catch((error: any) => {
reject(new SocialError(error.code, error.message))
})
})
}
private getUserProviderData = (userId: string) => {
return new Promise<UserProvider>((resolve,reject) => {
let userProviderRef = db.doc(`userProviderInfo/${userId}`)
userProviderRef.get().then((snapshot) => {
let userProvider: UserProvider = snapshot.data() as UserProvider || {}
resolve(userProvider)
})
.catch((error: any) => {
reject(new SocialError(error.code, 'firestore/getUserProviderData' + error.message))
})
})
}
}

View File

@@ -0,0 +1,5 @@
import { UserService } from './UserService'
export {
UserService
}

View File

@@ -0,0 +1,106 @@
// - Import react components
import { firebaseRef, firebaseAuth, db } from 'data/firestoreClient'
import { SocialError } from 'core/domain/common'
import { Vote } from 'core/domain/votes'
import { IVoteService } from 'core/services/votes'
/**
* Firbase vote service
*
* @export
* @class VoteService
* @implements {IVoteService}
*/
export class VoteService implements IVoteService {
public addVote: (vote: Vote)
=> Promise<string> = (vote) => {
return new Promise<string>((resolve,reject) => {
const postRef = db.doc(`posts/${vote.postId}`)
let voteRef = postRef.collection(`votes`)
.add(vote)
voteRef.then((result) => {
resolve(result.id)
/**
* Add score
*/
db.runTransaction((transaction) => {
return transaction.get(postRef).then((postDoc) => {
if (postDoc.exists) {
const post = postDoc.data()
let {votes, score} = post
if (!votes) {
votes = {}
}
if (!score) {
score = 0
}
const newScore = score + 1
votes[vote.userId] = true
transaction.update(postRef, { votes: { ...votes}, score: newScore })
}
})
})
})
.catch((error: any) => {
reject(new SocialError(error.code,error.message))
})
})
}
public getVotes: (postId: string)
=> Promise<{ [postId: string]: { [voteId: string]: Vote } }> = (postId) => {
return new Promise<{ [postId: string]: { [voteId: string]: Vote } }>((resolve,reject) => {
let votesRef = db.doc(`posts/${postId}`).collection(`votes`)
votesRef.onSnapshot((snapshot) => {
let parsedData: {[postId: string]: {[voteId: string]: Vote}} = {[postId]: {}}
snapshot.forEach((result) => {
parsedData[postId][result.id] = {
id: result.id,
...result.data() as Vote
}
})
resolve(parsedData)
})
})
}
public deleteVote: (vote: Vote)
=> Promise<void> = (vote) => {
return new Promise<void>((resolve,reject) => {
const batch = db.batch()
const postRef = db.doc(`posts/${vote.postId}`)
let voteRef = postRef.collection(`votes`).doc(vote.id!)
batch.delete(voteRef)
batch.commit().then(() => {
resolve()
/**
* Remove score
*/
db.runTransaction((transaction) => {
return transaction.get(postRef).then((postDoc) => {
if (postDoc.exists) {
const post = postDoc.data()
let {votes, score} = post
if (!votes) {
votes = {}
}
if (!score) {
score = 0
}
const newScore = score + 1
votes[vote.userId] = true
transaction.update(postRef, { votes: { ...votes}, score: newScore })
}
})
})
})
.catch((error) => {
reject(new SocialError(error.code,error.message))
})
})
}
}

View File

@@ -0,0 +1,5 @@
import { VoteService } from './VoteService'
export {
VoteService
}