Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
jekil committed Oct 2, 2013
0 parents commit 7a787b6
Show file tree
Hide file tree
Showing 141 changed files with 23,545 additions and 0 deletions.
52 changes: 52 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# Compiled source #
###################
*.com
*.class
*.dll
*.exe
*.o
*.so
*.pyc
*.pyo

# Packages #
############
# it's better to unpack these files and commit the raw source
# git has its own built in compression methods
*.7z
*.dmg
*.gz
*.iso
*.jar
*.rar
*.tar
*.zip

# Logs and databases #
######################
*.log
*.sql
*.sqlite

# OS generated files #
######################
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
Icon?
ehthumbs.db
Thumbs.db

# Development env #
###################
.project
.sublime-project
.pydevproject
.idea

# Ghiro custom files #
######################
ghiro/secret_key.py
logs/*
3 changes: 3 additions & 0 deletions analyses/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Ghiro - Copyright (C) 2013 Ghiro Developers.
# This file is part of Ghiro.
# See the file 'docs/LICENSE.txt' for license terms.
52 changes: 52 additions & 0 deletions analyses/forms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# Ghiro - Copyright (C) 2013 Ghiro Developers.
# This file is part of Ghiro.
# See the file 'docs/LICENSE.txt' for license terms.

import os
from django import forms
from django.conf import settings
from django.core.exceptions import ValidationError

from analyses.models import Case, Analysis

class CaseForm(forms.ModelForm):
"""Case form."""
class Meta:
model = Case

class UploadImageForm(forms.ModelForm):
"""Image upload form."""
image = forms.FileField(required=True)

class Meta:
model = Analysis
fields = ["image"]

def clean_image(self):
image = self.cleaned_data.get("image", False)
if image:
# File check.
if image._size > settings.MAX_FILE_UPLOAD:
raise ValidationError("Image file too large")
# Type check.
file_type = image.content_type
if not file_type in settings.ALLOWED_EXT:
raise ValidationError("Image type not supported.")
else:
raise ValidationError("Image field is mandatory.")

class ImageFolderForm(forms.Form):
"""Folder upload form."""
path = forms.CharField(required=True)

def clean_image(self):
path = self.cleaned_data.get("path", False)
if path:
# Checks if it exist.
if not os.path.exists(path):
raise ValidationError("Specified path not found.")
# Checks if is a directory.
if not os.path.isdir(path):
raise ValidationError("Specified path is not a directory.")
else:
raise ValidationError("Path field is mandatory.")
3 changes: 3 additions & 0 deletions analyses/management/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Ghiro - Copyright (C) 2013 Ghiro Developers.
# This file is part of Ghiro.
# See the file 'docs/LICENSE.txt' for license terms.
3 changes: 3 additions & 0 deletions analyses/management/commands/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Ghiro - Copyright (C) 2013 Ghiro Developers.
# This file is part of Ghiro.
# See the file 'docs/LICENSE.txt' for license terms.
68 changes: 68 additions & 0 deletions analyses/management/commands/process.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# Ghiro - Copyright (C) 2013 Ghiro Developers.
# This file is part of Ghiro.
# See the file 'docs/LICENSE.txt' for license terms.

import logging
from django.core.management.base import NoArgsCommand
from django.utils.timezone import now
from time import sleep

import analyzer.db as db
from analyses.models import Analysis
from analyzer.images import AnalyzerRunner
from analyzer.utils import HashComparer

logger = logging.getLogger("processor")

class Command(NoArgsCommand):
"""Process images on analysis queue."""

help = "Image processing"

option_list = NoArgsCommand.option_list

def handle(self, *args, **options):
"""Runs command."""
logger.debug("Starting processor...")

try:
self._process()
except KeyboardInterrupt:
print "Exiting... (requested by user)"
self.is_running = False

def _process(self):
"""Starts processing waiting tasks."""
self.is_running = True
while self.is_running:
# Fetch tasks waiting processing.
tasks = Analysis.objects.filter(state="W").order_by("id")

if tasks:
logger.info("Found {0} images waiting".format(tasks.count()))

for task in tasks:
logger.info("Processing task {0}".format(task.id))

try:
logger.debug("Processing task {0}".format(task.id))
# Process.
results = AnalyzerRunner(task.image_id, task.file_name).run()
task.analysis_id = db.save_results(results)
# Hash checks.
HashComparer.run(results["hash"], task)
# Complete.
task.state = "C"
logger.info("Processed task {0} with success".format(task.id))
except Exception as e:
logger.exception("Error processing task {0}: {1}".format(task.id, e))
task.state = "F"
finally:
# Save.
task.completed_at = now()
task.save()

logger.info("Done bunch")
else:
logger.debug("Waiting...")
sleep(1)
60 changes: 60 additions & 0 deletions analyses/management/commands/submit.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Ghiro - Copyright (C) 2013 Ghiro Developers.
# This file is part of Ghiro.
# See the file 'docs/LICENSE.txt' for license terms.

import magic
import os
from django.core.management.base import BaseCommand
from optparse import make_option

from analyses.models import Case, Analysis
from users.models import Profile
from analyzer.db import save_file
from analyzer.utils import create_thumb


class Command(BaseCommand):
"""Image submission via command line."""

option_list = BaseCommand.option_list + (
make_option("--target", "-t", dest="target",
help="Path of the file or directory to submit"),
make_option("--case", "-c", dest="case",
help="Case ID, images will be attached to it"),
make_option("--username", "-u", dest="username",
help="Username"),
)

help = "Task submission"

def handle(self, *args, **options):
"""Runs command."""
# Get options.
user = Profile.objects.get(username=options["username"].strip())
case = Case.objects.get(pk=options["case"].strip())

# Add directory or files.
if os.path.isdir(options["target"]):
for file_name in os.listdir(options["target"]):
print "INFO: processing {0}".format(file_name)
self._add_task(os.path.join(options["target"], file_name), case, user)
elif os.path.isfile(options["target"]):
print "INFO: processing {0}".format(options["target"])
self._add_task(options["target"], case, user)
else:
print "ERROR: target is not a file or directory"

def _add_task(self, file, case, user):
"""Adds a new task to database.
@param file: file path
@param case: case id
@param user: user id
"""
task = Analysis()
task.owner = user
task.case = case
task.file_name = os.path.basename(file)
mime = magic.Magic(mime=True)
task.image_id = save_file(file_path=file, content_type=mime.from_file(file))
task.thumb_id = create_thumb(file)
task.save()
81 changes: 81 additions & 0 deletions analyses/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# Ghiro - Copyright (C) 2013 Ghiro Developers.
# This file is part of Ghiro.
# See the file 'docs/LICENSE.txt' for license terms.


from bson.objectid import ObjectId
from django.db import models
from django.conf import settings

from ghiro.common import mongo_connect
from users.models import Profile

db = mongo_connect()

class Case(models.Model):
"""Collection of image analysis."""

# Case state.
STATUSES = (
("O", "Open"),
("C", "Closed")
)
name = models.CharField(max_length=255, null=False, blank=False)
description = models.TextField(null=True, blank=True)
state = models.CharField(max_length=1, choices=STATUSES, default="O", db_index=True, editable=False, null=False, blank=False)
owner = models.ForeignKey(Profile, null=False, blank=False, on_delete=models.CASCADE, db_index=True, editable=False, related_name="owned_cases")
users = models.ManyToManyField(Profile, null=True, blank=True, db_index=True, related_name="cases")
created_at = models.DateTimeField(auto_now_add=True, editable=False, db_index=True)
updated_at = models.DateTimeField(auto_now=True, editable=False)

class Meta:
ordering = ["-created_at"]

def save(self, *args, **kwargs):
self.name = self.name.strip()
if self.description:
self.description = self.description.strip()
super(Case, self).save(*args, **kwargs)

class Analysis(models.Model):
"""Image analysis."""

STATUSES = (
("W", "Waiting"),
("C", "Completed"),
("F", "Failed")
)
image_id = models.CharField(max_length=72, editable=False, null=False, blank=False)
thumb_id = models.CharField(max_length=72, editable=False, null=True, blank=True)
file_name = models.CharField(max_length=255, editable=False, null=False, blank=False)
analysis_id = models.CharField(max_length=24, db_index=True, editable=False, null=True, blank=True)
case = models.ForeignKey(Case, null=False, blank=False, on_delete=models.CASCADE, db_index=True, editable=False, related_name="images")
owner = models.ForeignKey(Profile, null=False, blank=False, on_delete=models.CASCADE, db_index=True, editable=False, related_name="owned_images")
state = models.CharField(max_length=1, choices=STATUSES, default="W", db_index=True, editable=False)
created_at = models.DateTimeField(auto_now_add=True, editable=False, db_index=True)
completed_at = models.DateTimeField(null=True, blank=True)

class Meta:
ordering = ["-created_at"]

@property
def latitude(self):
"""Lookups latitude on mongo."""
try:
record = db.analyses.find_one({"_id": ObjectId(self.analysis_id)})
except:
return None

if "gps" in record["metadata"]:
return record["metadata"]["gps"]["pos"]["Latitude"]

@property
def longitude(self):
"""Lookups longitude on mongo."""
try:
record = db.analyses.find_one({"_id": ObjectId(self.analysis_id)})
except:
return None

if "gps" in record["metadata"]:
return record["metadata"]["gps"]["pos"]["Longitude"]
3 changes: 3 additions & 0 deletions analyses/templatetags/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Ghiro - Copyright (C) 2013 Ghiro Developers.
# This file is part of Ghiro.
# See the file 'docs/LICENSE.txt' for license terms.
Loading

0 comments on commit 7a787b6

Please sign in to comment.