Ejemplo n.º 1
0
	def POST(self, *args, **kwargs):
		"""
			if id is set, we edit corresponding link, else we create new one
		"""
		if 'id' in kwargs:
			#link = filter(lambda x: x.id == int(kwargs['id']), Link)
			lid = int(kwargs['id'])
			link = list(filter(lambda x: x.id == lid, Link))

			if len(link) == 0:
				return routing.HTTP_400("'%s' id not found" % kwargs['id'])
			link = link[0]
		else:
			link = Link()

		errors = {}
		# simple fields
		for name, mandatory in {'link': True, 'name': True, 'description': False}.iteritems():
			#NOTE: mandatory fields must be non-null (or empty size)
			#      others can be unset or empty
			if mandatory and (name not in kwargs or len(kwargs[name])) == 0:
				errors[name] = (10, 'field required'); continue
			elif name not in kwargs:
				continue

			try:
				value = link.fieldesc(name).cast(kwargs[name])
			except ValueError:
				errors[name] = (11, 'invalid type'); continue

			setattr(link, name, value)

		# test link is unique
		#TODO: must be done at ORM level (with save() method)

		_link = link.link
		if 'name' not in errors and not link.saved() and\
				len(filter(lambda x: x.link == _link, Link)) > 0:
			errors['link'] = (13, 'not unique')

		# relational field: tags. we get tag names as input...
		tagnames = kwargs['tags'] # tentacles workaroung
		if len(tagnames) == 0:
			errors['tags'] = (12, 'at least one value required')
		else:
			tags     = list(filter(lambda t: t.name in tagnames, Tag))
			newtags  = [Tag(name=name) for name in tagnames if name not in [t.name for t in tags]]

			for t in link.tags:
				tags.remove(t) if t in tags else link.tags.remove(t)

			for t in set(tags).union(newtags):
				link.tags.append(t)


		if len(errors) > 0:
			return routing.HTTP_409(errors), link

		link.save()
		return routing.HTTP_200(link.id), link
Ejemplo n.º 2
0
	def PUT(self, content):
		if 'link' not in content or 'name' not in content:
			return routing.HTTP_400("link, name are mandatory keys")
		
		if 'id' in content and len(filter(lambda x: x.id == content['id'], Link)) > 0:
			return routing.HTTP_400("id already exists")
		if len(filter(lambda x: x.link == content['link'], Link)) > 0:
			return routing.HTTP_400("link must be unique")

		link = Link()
		for key, value in content.iteritems():
			if key == 'tags':
				continue

			if not key in link.__fields__:
				return routing.HTTP_409("unknown field '%s'" % key)
				
			setattr(link, key, value)

		"""We query all tags (by tagname), and create new ones"""
		if 'tags' in content:
			link.tags = list(filter(lambda t: t.name in content['tags'], Tag))
			link.tags.extend([Tag(name=t) for t in content['tags'] if t not in [tag.name for tag in link.tags]])

		link.save()
		return link.id
Ejemplo n.º 3
0
	def bytag(self, tagname):
		#short query form is not available for now
		#res = list(filter(lambda x: tagname in [name for tag in x.tags], Link))
		tags = list(filter(lambda l: l.name == tagname, Tag))
		if len(tags) == 0:
			return routing.HTTP_404()

		tag0 = tags[0]
		return list(map(lambda l: l.id, filter(lambda l: tag0 in l.tags, Link)))
Ejemplo n.º 4
0
	def _binary(self, field, request, id, content):
		link = list(filter(lambda x: x.id == id, Link))
		if len(link) == 0:
			return routing.HTTP_404()
		link = link[0]

		if request.method == 'PUT':
			setattr(link, field, content.read())
			link.save()

			return None

		elif request.method == 'DELETE':
			setattr(link, field, None)
			link.save()
			return None

		# GET
		data = getattr(link, field)
		if data is None:
			return routing.HTTP_204()

		import magic
		m = magic.open(magic.MAGIC_MIME)
		m.load()
		mime = m.buffer(data)
		m.close()

		if mime is not None and len(mime) > 0:
			request.setHeader('Content-Type', mime.split(';')[0])
		request.write(str(getattr(link, field)))
		request.finish()
		
		return server.NOT_DONE_YET
Ejemplo n.º 5
0
	def PUT(self, content):
		if 'name' not in content:
			return (400, "*name* key is mandatory")
		
		if 'id' in content and len(filter(lambda x: x.id == content['id'], Tag)) > 0:
			return (400, "id already exists")
		if len(filter(lambda x: x.link == content['name'], Tag)) > 0:
			return (400, "name must be unique")

		tag = Tag()
		for key, value in content.iteritems():
			if not key in tag.__fields__:
				return(409, "unknown field '%s'" % key)
				
			setattr(tag, key, value)
		tag.save()
		return tag.id
Ejemplo n.º 6
0
	def DELETE(self, id):
		"""
		
			NOTE: associated tags, even if specially created for this link, are not deleted
		"""
		tags = list(filter(lambda x: x.id == id, Tag))
		if len(tags) == 0:
			return (404, "not found")
		elif len(tags) > 1:
			return (500, "return several tags for the same id")

		tags[0].delete()
		return (200, True)
Ejemplo n.º 7
0
	def DELETE(self, id):
		"""
		
			NOTE: associated tags, even if specially created for this link, are not deleted
		"""
		links = list(filter(lambda x: x.id == id, Link))
		if len(links) == 0:
			return routing.HTTP_404("not found")
		elif len(links) > 1:
			return routing.HTTP_500("return several links for the same id")

		links[0].delete()
		return routing.HTTP_200()
Ejemplo n.º 8
0
	def GET(self, id, **kwargs):
		tag = list(filter(lambda x: x.id == id, Tag))
		if len(tag) == 0:
			return (404, None)

		tag = tag[0]
		res  = {}
		for name, fld in tag.__fields__.iteritems():
			if isinstance(fld, Reference):
				continue

			res[name] = getattr(tag, name)

		return res
Ejemplo n.º 9
0
def search(q, **kwargs):
	"""

		search format:
			a+b-c+"d e"-"f+g"
			give tags: +a, +b, -c, +d e, -f g


		NOTES: 
			. in url encoding, '+' == space and '& %2B == '+'
			  we accept both as plus sign (+ is visually better)

	"""
	# parse querystring
	print 'search=', q

	"""
	import shlex
	def sign(tag):
		if tag[0] in ('+', '-'):
			return (tag[0], tag[1:].decode('utf8'))
		return ('+', tag.decode('utf8'))
	tags = [sign(tag) for tag in shlex.split(q)]
	"""
	import re
	tags = [(s if s == '-' else '+', t.strip('"')) for (s, t) in re.findall("(^|[ +-])([^\" +-]+|\"[^\"]+\")", q)]

	plus  = map(lambda t: t[1], filter(lambda t: t[0] == '+', tags))
	minus = map(lambda t: t[1], filter(lambda t: t[0] == '-', tags))

	plus  = list(filter(lambda t: t.name in plus, Tag))
	minus = list(filter(lambda t: t.name in minus, Tag))

	links = list(filter(lambda l: l.tags.issuperset(plus) and l.tags.isdisjoint(minus), Link))

	#TODO: howto made it simple/clearer ?
	def rset(tag, sign):
		setattr(tag, 'sign', sign); return tag
	tags = map(lambda t: rset(t, '+'), plus)
	tags.extend(map(lambda t: rset(t, '-'), minus))
	tags.sort(key=lambda t: t.name)

	related = list(filter(lambda t: not t.Link__tags.isdisjoint(links) and t not in	plus, Tag))

	return Template('tag.html',
		title="Tag ☄ "+q,
		#query=q,
		tagname=q,
		links=links,
		tags=tags,
		related=related
	)
Ejemplo n.º 10
0
	def GET(self, id, __referer__=None, **kwargs):
		link = list(filter(lambda x: x.id == id, Link))
		if len(link) == 0:
			return routing.HTTP_404("%s link not found" % id)

		link = link[0]
		res  = {}
		for name, fld in link.__fields__.iteritems():
			if isinstance(fld, Reference):
				continue

			res[name] = getattr(link, name)
			#TODO: should be done in a generic way
			# the best way should probably be to have a tentacles json backend
			# For that, we need to be able to switch backend for an object
			
			# JSON encoder should also understand datetime object
			if isinstance(fld, Datetime) and res[name] is not None:
				res[name] = str(res[name])

		res['tags'] = dict([(t.name, None) for t in link.tags])
		return res
Ejemplo n.º 11
0
	def initialize(self, root):
		plugins = filter(lambda x: x.active is True, Plugin)

		for plugin in plugins:
			try:
				sys.path.insert(0, plugin.path)
				mod = __import__(plugin.name, globals(), locals(), [], -1)
			except ImportError, e:
				print "/!\ Cannot import %s plugin:" % plugin.name, e

			mod.CONTEXT = AppContext(mod)
			mod.PLUGIN  = plugin
			plugin.MODULE = mod

			plugin.root = PluginNode(plugin)
			root.putChild(plugin.name, plugin.root)
			self.plugins[plugin.name] = plugin

			# check UUID matching
			if mod.UUID != plugin.uuid:
				print "/!\ plugin UUID does not match database one (%s vs %s)" % \
					(plugin.uuid, mod.UUID)
				continue

			# set default values 
			#TODO: use a generic directory
			#TODO: should be done earlier, before @callback decorators were called
			if not hasattr(mod, 'AUTHENTICATION'):
				mod.AUTHENTICATION = False

			# load URL callbacks
			raw_urls = mod.__dict__.get('URLS', {})
			for url, target in raw_urls.iteritems():
				"""Looping on URLs

				we must determine if url is:
				. a raw string		(i.e: /foo/bar)
				. a simple regex  (i.e: /foo/{bar})
				. a full regex		(i.e: /foo/(?<bar>[^/]+))
				"""
				if not isinstance(target, (tuple,list)):
					target = (target,)

				for _target in target:
					if isinstance(_target, static.File):
						content_type = _target.content_type if hasattr(_target,'content_type') else '*/*'
						plugin.addurl(url, content_type, _target); 
						continue
					elif isinstance(_target, template.Template):
						plugin.addurl(url, _target.content_type, TemplateNode(mod, _target)); continue
			

					# resolve unbound methods
					if hasattr(_target, 'im_self') and _target.im_self is None:
						#callback = getattr(self.instances[callback.im_class], callback.__name__)
						#callback = getattr(self.__classinstance(callback.im_class), callback.__name__)
						_target = self.boundmethod(_target)

					if not hasattr(_target, '__callable__'):
						raise Exception('%s is not callable' % _target.__name__)
					elif 'url' in _target.__callable__:
						raise Exception("%s url cannot be redefined (is %s, try to set %s)" %\
							(_target.__name__, _target.__callable__['url'], url))

					_target.__callable__['url'] = url
					plugin.addurl(url, _target.__callable__['content_type'], FuncNode(_target))


			# load plugin callbacks
			"""
				mod.__callbacks__ contains callback functions but we don't
				know at which classes it belongs (cause when decorator is called,
				class methods are not yet binded to its class)
				
				What we try to do here is to find method parent class.
				
				NOTE: for the moment, we only search at level 1 (no recursion)
			"""
			for (name, obj) in inspect.getmembers(mod):
				if inspect.isfunction(obj) and '__callable__' in dir(obj):
					#netnode.putChild(name, FuncNode(obj))
					# get original url if not set explicitly
					if 'url' not in obj.__callable__:
						obj.__callable__['url'] = obj.__callable__['_url']

					node = FuncNode(obj)
					plugin.addurl(node.url, obj.__callable__['content_type'], node)
			
				#NOTE: why limited to callable objects only
				elif inspect.isclass(obj) and issubclass(obj, Callable) and obj is not Callable:
					self.__classinit(obj, plugin)