diff --git a/database/migrations/20200112223826-create-files-likes-table.js b/database/migrations/20200112223826-create-files-likes-table.js new file mode 100644 index 0000000000000000000000000000000000000000..f8122036754e45913b4540a3af8b7d4ddec11cd4 --- /dev/null +++ b/database/migrations/20200112223826-create-files-likes-table.js @@ -0,0 +1,39 @@ +module.exports = { + up: (migration, Types) => { + return migration.createTable('user_file_likes', { + user_id: { + type: Types.UUID, + references: { + model: 'users', + key: 'id', + }, + }, + file_id: { + type: Types.UUID, + references: { + model: 'files', + key: 'id', + }, + }, + created_at: { + type: Types.DATE, + defaultValue: Types.fn('now'), + allowNull: false, + }, + updated_at: { + type: Types.DATE, + defaultValue: Types.fn('now'), + allowNull: false, + }, + deleted_at: { + type: Types.DATE, + defaultValue: null, + allowNull: true, + }, + }) + }, + + down: (migration, Types) => { + return migration.dropTable('user_file_likes') + }, +} \ No newline at end of file diff --git a/src/database/models/User.js b/src/database/models/User.js index 4c50244556200187afa2c4ea917a42cb0f56f7af..3cbc758c5d54a4287401cd3dadb08029139cc46a 100644 --- a/src/database/models/User.js +++ b/src/database/models/User.js @@ -124,6 +124,7 @@ module.exports = (sequelize, DataTypes) => { Model.hasMany(models.AccessToken, { foreignKey: 'user_id' }) Model.hasMany(models.RefreshToken, { foreignKey: 'user_id' }) Model.hasMany(models.File, { foreignKey: 'user_id' }) + Model.belongsToMany(models.File, { as: 'likes', through: 'user_file_likes', foreignKey: 'user_id', otherKey: 'file_id' }) } Model.relations = [ diff --git a/src/http/controllers/api/storage.js b/src/http/controllers/api/storage.js index 966a899a33c178d64ce48450ceb73a346de898c5..eb26474e2ae095c7053605c8a47b587a8504da5a 100644 --- a/src/http/controllers/api/storage.js +++ b/src/http/controllers/api/storage.js @@ -1,5 +1,5 @@ const { Storage } = require('@google-cloud/storage') -const { sequelize, File, User } = require('database/models') +const { Sequelize, File } = require('database/models') const HttpError = require('core/errors/HttpError') const mimeType = require('mime-types') const uuid = require('uuid/v4') @@ -19,7 +19,7 @@ exports.saveFile = async ctx => { } const { file } = ctx - const { tags = [], title } = ctx.request.body + const { tags = [], title, remote_id } = ctx.request.body const fileinfo = { meta: { @@ -33,13 +33,16 @@ exports.saveFile = async ctx => { stream: 'plastics-public', provider: 'google', comment: title, - tags, + tags : Array.isArray(tags) ? tags : [tags], approved: true, featured: true, } - console.log(fileinfo) - const persistedFile = await File.create(fileinfo) + if (remote_id) { + fileinfo.meta.remote_id = remote_id + } + + const persistedFile = await File.create(fileinfo).catch(e => console.error(e) || null) const storagePath = `${ fileinfo.file_root }/${ fileinfo.file_name }` const bucket = storage.bucket(env('GCS_BUCKET')) @@ -56,12 +59,79 @@ exports.saveFile = async ctx => { } } } - const uploadedFile = await bucket.upload(file.path, uploadOpts) - // await bucket.file(storagePath).makePublic() - console.log(uploadedFile) + await bucket.upload(file.path, uploadOpts) ctx.body = { file: persistedFile, } } + +exports.feed = async ctx => { + const includes = [] + + const user = await ctx.services.authService.getUser() + if (user) { + includes.push([ + Sequelize.literal(`exists (select * from user_file_likes where user_file_likes.user_id='${ user.id }' and user_file_likes.file_id="File".id)`), + 'liked', + ]) + } else { + includes.push([ + Sequelize.literal('false'), + 'liked', + ]) + } + + ctx.body = { + feed: (await File.findAll({ + where: { + approved: true, + }, + order: [['created_at', 'desc']], + attributes: { + include: includes, + exclude: [ + 'labels', + 'updated_at', + 'requires_approval', + 'labels', + ] + } + })).map(inst => ({ + ...inst.toJSON(), + liked: inst.get('liked'), + })) + } +} + +exports.like = async ctx => { + const { fileId } = ctx.params + + const user = await ctx.services.authService.getUser() + if (!user) { + throw new HttpError({ status: 403, title: 'Must be signed in to like an image', description: 'You must be signed in to like images' }) + } + const file = await File.findOne({ where: { id: fileId }}) + if (!file) { + throw new HttpError({ status: 404, title: 'Could not find image', description: 'Could not find image to like' }) + } + + await user.addLike(file) + ctx.body = { file: {...file.toJSON(), liked: true }} +} +exports.unlike = async ctx => { + const { fileId } = ctx.params + + const user = await ctx.services.authService.getUser() + if (!user) { + throw new HttpError({ status: 403, title: 'Must be signed in to like an image', description: 'You must be signed in to unlike images' }) + } + const file = await File.findOne({ where: { id: fileId }}) + if (!file) { + throw new HttpError({ status: 404, title: 'Could not find image', description: 'Could not find image to unlike' }) + } + + await user.removeLike(file) + ctx.body = { file: {...file.toJSON(), liked: false }} +} \ No newline at end of file diff --git a/src/http/routes.js b/src/http/routes.js index 5e4e05348f90ee16bef2a8e9ac41cedc7da4fd94..c11c9c2b7c1bdcc91f96a754ef1cc7f23108a98b 100644 --- a/src/http/routes.js +++ b/src/http/routes.js @@ -30,6 +30,9 @@ api.post('/metrics', controller('api/content', 'postMetric')) api.get('/metrics', controller('api/content', 'getWithin')) api.post('/feature', upload.single('featured_image'), controller('api/storage', 'saveFile')) +api.get('/feed', upload.single('featured_image'), controller('api/storage', 'feed')) +api.post('/feed/:fileId/like',controller('api/storage', 'like')) +api.post('/feed/:fileId/unlike', controller('api/storage', 'unlike')) api.post('/register', controller('api/auth', 'register')) api.post('/login', controller('api/auth', 'login'))