Skip to content

Commit

Permalink
nextcloud integration, multi user with sharing / public
Browse files Browse the repository at this point in the history
  • Loading branch information
Hooram Nam committed Jul 11, 2018
1 parent 1412ed8 commit d4a4ac0
Show file tree
Hide file tree
Showing 15 changed files with 632 additions and 119 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,5 @@ protected_media
.vscode
.coverage
htmlcov
samplephotos
samplephotos
nextcloud_media
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ ENV DB_HOST database
ENV DB_PORT 5432

ENV BACKEND_HOST localhost

ENV FRONTEND_HOST localhost

# REDIS location
ENV REDIS_HOST redis
Expand Down
37 changes: 27 additions & 10 deletions api/api_util.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from api.models import Photo, Face, Person, AlbumAuto, AlbumDate, AlbumUser
from api.models import Photo, Face, Person, AlbumAuto, AlbumDate, AlbumUser, LongRunningJob

import numpy as np

Expand All @@ -17,7 +17,7 @@
from sklearn.cluster import MeanShift, estimate_bandwidth

from django.db.models.functions import TruncMonth
from django.db.models import Sum, Count
from django.db.models import Sum, Count, Q, Prefetch

from nltk.corpus import stopwords

Expand All @@ -31,6 +31,13 @@
import pandas as pd
from api.util import logger

def get_current_job():
job_detail = None
running_job = LongRunningJob.objects.filter(
finished=False).order_by('-started_at').first()
if running_job:
job_detail = LongRunningJobSerializer(running_job).data
return job_detail

def shuffle(l):
random.shuffle(l)
Expand Down Expand Up @@ -114,8 +121,8 @@ def get_location_timeline():
return data


def get_search_term_examples():
pp = Photo.objects.exclude(geolocation_json={}).exclude(
def get_search_term_examples(user):
pp = Photo.objects.filter(owner=user).exclude(geolocation_json={}).exclude(
exif_timestamp=None).exclude(
captions_json={}).prefetch_related('faces__person')

Expand Down Expand Up @@ -201,18 +208,28 @@ def get_search_term_examples():
return list(set(search_terms))


def get_count_stats():
num_photos = Photo.objects.count()
num_faces = Face.objects.count()
def get_count_stats(user):
num_photos = Photo.objects.filter(owner=user).count()
num_faces = Face.objects.filter(photo__owner=user).count()
num_unknown_faces = Face.objects.filter(
Q(person__name__exact='unknown') & Q(photo__owner=user)).count()
num_labeled_faces = Face.objects.filter(
Q(person_label_is_inferred=False) & ~Q(person__name__exact='unknown') &
Q(photo__owner=user)).count()
num_inferred_faces = Face.objects.filter(
Q(person_label_is_inferred=True) & Q(photo__owner=user)).count()
num_people = Person.objects.count()
num_albumauto = AlbumAuto.objects.count()
num_albumdate = AlbumDate.objects.count()
num_albumuser = AlbumUser.objects.count()
num_albumauto = AlbumAuto.objects.filter(owner=user).count()
num_albumdate = AlbumDate.objects.filter(owner=user).count()
num_albumuser = AlbumUser.objects.filter(owner=user).count()

res = {
"num_photos": num_photos,
"num_faces": num_faces,
"num_people": num_people,
"num_unknown_faces": num_unknown_faces,
"num_labeled_faces": num_labeled_faces,
"num_inferred_faces": num_inferred_faces,
"num_albumauto": num_albumauto,
"num_albumdate": num_albumdate,
"num_albumuser": num_albumuser,
Expand Down
4 changes: 2 additions & 2 deletions api/directory_watcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,9 @@ def scan_photos(user):
with open(img_abs_path, "rb") as f:
for chunk in iter(lambda: f.read(4096), b""):
hash_md5.update(chunk)
image_hash = hash_md5.hexdigest()
image_hash = hash_md5.hexdigest() + str(user.id)
elapsed = (datetime.datetime.now() - start).total_seconds()
util.logger.info('generating md5 took %.2f' % elapsed)
util.logger.info('generating md5 took %.2f, image_hash: %s' % (elapsed,image_hash))

# qs = Photo.objects.filter(image_hash=image_hash)

Expand Down
8 changes: 6 additions & 2 deletions api/face_classify.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,13 +146,16 @@ def train_faces(user):
face.person_label_probability = probability
face.save()

res = cluster_faces()
# res = cluster_faces()
# print(res)

lrj = LongRunningJob.objects.get(job_id=rq.get_current_job().id)
lrj.finished = True
lrj.failed = False
lrj.finished_at = datetime.datetime.now()
lrj.result = res
lrj.result = {}
lrj.save()
return True

except:
res = []
Expand All @@ -162,6 +165,7 @@ def train_faces(user):
lrj.finished = True
lrj.finished_at = datetime.datetime.now()
lrj.save()
return False

return res

Expand Down
47 changes: 43 additions & 4 deletions api/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@
from io import StringIO

import ipdb
from django_cryptography.fields import encrypt


geolocator = Nominatim()
default_tz = pytz.timezone('Asia/Seoul')
Expand Down Expand Up @@ -83,10 +85,16 @@ class User(AbstractUser):
scan_directory = models.CharField(max_length=512, db_index=True)
avatar = models.ImageField(upload_to='avatars', null=True)

nextcloud_server_address = models.CharField(max_length=200,default=None,null=True)
nextcloud_username = models.CharField(max_length=64,default=None,null=True)
nextcloud_app_password = encrypt(models.CharField(max_length=64,default=None,null=True))
nextcloud_scan_directory = models.CharField(max_length=512, db_index=True,null=True)


class Photo(models.Model):
image_path = models.FilePathField(max_length=512, db_index=True)
image_hash = models.CharField(primary_key=True, max_length=32, null=False)
image_path = models.CharField(max_length=512, db_index=True)
# md5_{user.id}
image_hash = models.CharField(primary_key=True, max_length=64, null=False)

thumbnail = models.ImageField(upload_to='thumbnails')
thumbnail_tiny = models.ImageField(upload_to='thumbnails_tiny')
Expand Down Expand Up @@ -127,11 +135,39 @@ class Photo(models.Model):
public = models.BooleanField(default=False, db_index=True)

def _generate_md5(self):
print(self.owner.id)
hash_md5 = hashlib.md5()
with open(self.image_path, "rb") as f:
for chunk in iter(lambda: f.read(4096), b""):
hash_md5.update(chunk)
self.image_hash = hash_md5.hexdigest()
self.image_hash = hash_md5.hexdigest() + str(self.owner.id)
print(self.image_hash)

def _generate_captions_im2txt(self):
image_path = self.thumbnail.path
captions = self.captions_json
search_captions = self.search_captions
try:
caption = im2txt(image_path)
caption = caption.replace("<start>", '').replace(
"<end>", '').strip().lower()
captions['im2txt'] = caption
self.captions_json = captions
# todo: handle duplicate captions
self.search_captions = search_captions + caption
self.save()
util.logger.info(
'generated im2txt captions for image %s. caption: %s' %
(image_path, caption))
return True
except:
util.logger.warning(
'could not generate im2txt captions for image %s' %
image_path)
return False




def _generate_captions(self):
image_path = self.thumbnail.path
Expand Down Expand Up @@ -759,7 +795,7 @@ def __str__(self):


class AlbumUser(models.Model):
title = models.CharField(unique=True, max_length=512)
title = models.CharField(max_length=512)
created_on = models.DateTimeField(auto_now=True, db_index=True)
photos = models.ManyToManyField(Photo)
cover_photos = models.ManyToManyField(
Expand All @@ -774,6 +810,9 @@ class AlbumUser(models.Model):

public = models.BooleanField(default=False, db_index=True)

class Meta:
unique_together = ('title', 'owner')


class LongRunningJob(models.Model):
JOB_SCAN_PHOTOS = 1
Expand Down
31 changes: 31 additions & 0 deletions api/nextcloud.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
from api.models import *
import owncloud as nextcloud
import ipdb
import time

def login(user):
nc = nextcloud.Client(user.nextcloud_server_address)
nc.login(user.nextcloud_username, user.nextcloud_app_password)

def path_to_dict(path):
print(path)
d = {'title': os.path.basename(path), 'absolute_path': path}
try:
d['children'] = [
path_to_dict(os.path.join(path, x.path)) for x in nc.list(path)
if x.is_dir()
]
except:
pass

return d



def list_dir(user,path):
nc = nextcloud.Client(user.nextcloud_server_address)
nc.login(user.nextcloud_username, user.nextcloud_app_password)
return [p.path for p in nc.list(path) if p.is_dir()]



21 changes: 20 additions & 1 deletion api/permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,23 @@ def has_object_permission(self, request, view, obj):
return True

# Write permissions are only allowed to the owner of the snippet.
return obj == request.user
return obj == request.user


class IsPhotoOrAlbumSharedTo(permissions.BasePermission):
"""
Custom permission to only allow owners of an object to edit it.
"""

def has_object_permission(self, request, view, obj):
if obj.public:
return True

if obj.owner == request.user or request.user in obj.shared_to.all():
return True

for album in obj.albumuser_set.only('shared_to'):
if request.user in album.shared_to.all():
return True

return False
Loading

0 comments on commit d4a4ac0

Please sign in to comment.