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'))