Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Alchemy Api callable added.

  • Loading branch information...
commit 2ebbb228713e059c85556df3258651a360783f17 1 parent 15af0c3
Daniele Guido authored
864 glue/AlchemyAPI.py
View
@@ -0,0 +1,864 @@
+
+import urllib, json
+import sys
+
+from xml.etree import ElementTree as etree
+
+class AlchemyAPI_Params(object):
+ _url = ""
+ _html = ""
+ _text = ""
+ _outputMode = "json"
+ _customParameters = ""
+ def getUrl(self):
+ return self._url
+ def setUrl(self, url):
+ self._url = url
+ def getHtml(self):
+ return self._html
+ def setHtml(self, html):
+ self._html = html
+ def getText(self):
+ return self._text
+ def setText(self, text):
+ self._text = text
+ def getOutputMode(self):
+ return self._outputMode
+ def setOutputMode(self, mode):
+ if mode != "xml":
+ raise Exception, 'Error setting output mode.'
+ self._outputMode = mode
+ def getCustomParameters(self):
+ return self._customParameters
+ def setCustomParameters(self, *values):
+ self._customParameters = ""
+ for i in len(values):
+ self._customParameters += "&" + values[i] + "=" + urllib.quote(values[i + 1])
+ i = i + 1
+ def getParameterString(self):
+ retString = ""
+ if self._url != "":
+ retString += "&url=" + urllib.quote(self._url)
+ if self._html != "":
+ retString += "&html=" + urllib.quote(self._html)
+ if self._text != "":
+ retString += "&text=" + urllib.quote(self._text)
+ if self._outputMode != "":
+ retString += "&outputMode=" + urllib.quote(self._outputMode)
+ if self._customParameters != "":
+ retString += self._customParameters
+ return retString
+
+
+class AlchemyAPI_NamedEntityParams(AlchemyAPI_Params):
+ _disambiguate = ""
+ _linkedData = ""
+ _coreference = ""
+ _quotations = ""
+ _sourceText = ""
+ _showSourceText = ""
+ _maxRetrieve = ""
+ _baseUrl = ""
+ _cQuery = ""
+ _xPath = ""
+ _sentiment = ""
+ def getDisambiguate(self):
+ return self._disambiguate
+ def setDisambiguate(self, setting):
+ if setting != 1:
+ if setting != 0:
+ raise Exception, 'Error setting Disambiguate.'
+ self._disambiguate = setting
+ def getLinkedData(self):
+ return self._linkedData
+ def setLinkedData(self, setting):
+ if setting != 1:
+ if setting != 0:
+ raise Exception, 'Error setting LinkedData.'
+ self._linkedData = setting
+ def getCoreference(self):
+ return self._coreference
+ def setCoreference(self, setting):
+ if setting != 1:
+ if setting != 0:
+ raise Exception, 'Error setting Coreference.'
+ self._coreference = setting
+ def getQuotations(self):
+ return self._quotations
+ def setQuotations(self, setting):
+ if setting != 1:
+ if setting != 0:
+ raise Exception, 'Error setting Quotations.'
+ self._quotations = setting
+ def getShowSourceText(self):
+ return self._showSourceText
+ def setShowSourceText(self, setting):
+ if setting != 1:
+ if setting != 0:
+ raise Exception, 'Error setting ShowSourceText.'
+ self._showSourceText = setting
+ def getSourceText(self):
+ return self._quotations
+ def setSourceText(self, setting):
+ if setting != 'cleaned_or_raw':
+ if setting != 'cleaned':
+ if setting != 'raw':
+ if setting != 'cquery':
+ if setting != 'xpath':
+ raise Exception, 'Error setting SourceText.'
+ self._sourceText = setting
+ def getMaxRetrieve(self):
+ return self._maxRetrieve
+ def setMaxRetrieve(self, setting):
+ self._maxRetrieve = setting
+ def getBaseUrl(self):
+ return self._baseUrl
+ def setBaseUrl(self, setting):
+ self._baseUrl = setting
+ def getConstraintQuery(self):
+ return self._cQuery
+ def setConstraintQuery(self, setting):
+ self._cQuery = setting
+ def getXPath(self):
+ return self._xPath
+ def setXPath(self, setting):
+ self._xPath = setting
+ def getSentiment(self):
+ return self._sentiment
+ def setSentiment(self, setting):
+ if setting != 1:
+ if setting != 0:
+ raise Exception, 'Error setting Sentiment.'
+ self._sentiment = setting
+ def getParameterString(self):
+ retString = super(AlchemyAPI_NamedEntityParams, self).getParameterString()
+ if self._disambiguate != "":
+ retString += "&disambiguate=" + str(self._disambiguate)
+ if self._linkedData != "":
+ retString += "&linkedData=" + str(self._linkedData)
+ if self._coreference != "":
+ retString += "&coreference=" + str(self._coreference)
+ if self._quotations != "":
+ retString += "&quotations=" + str(self._quotations)
+ if self._sourceText != "":
+ retString += "&sourceText=" + urllib.quote(self._sourceText)
+ if self._showSourceText != "":
+ retString += "&showSourceText=" + str(self._showSourceText)
+ if self._maxRetrieve != "":
+ retString += "&maxRetrieve=" + str(self._maxRetrieve)
+ if self._baseUrl != "":
+ retString += "&baseUrl=" + urllib.quote(self._baseUrl)
+ if self._cQuery != "":
+ retString += "&cquery=" + urllib.quote(self._cQuery)
+ if self._xPath != "":
+ retString += "&xpath=" + urllib.quote(self._xPath)
+ if self._sentiment != "":
+ retString += "&sentiment=" + str(self._sentiment)
+ return retString
+
+
+class AlchemyAPI_CategoryParams(AlchemyAPI_Params):
+ _sourceText = ""
+ _baseUrl = ""
+ _cQuery = ""
+ _xPath = ""
+ def getSourceText(self):
+ return self._quotations
+ def setSourceText(self, setting):
+ if setting != 'cleaned_or_raw':
+ if setting != 'cquery':
+ if setting != 'xpath':
+ raise Exception, 'Error setting SourceText.'
+ self._sourceText = setting
+ def getBaseUrl(self):
+ return self._baseUrl
+ def setBaseUrl(self, setting):
+ self._baseUrl = setting
+ def getConstraintQuery(self):
+ return self._cQuery
+ def setConstraintQuery(self, setting):
+ self._cQuery = setting
+ def getXPath(self):
+ return self._xPath
+ def setXPath(self, setting):
+ self._xPath = setting
+ def getParameterString(self):
+ retString = super(AlchemyAPI_CategoryParams, self).getParameterString()
+ if self._sourceText != "":
+ retString += "&sourceText=" + urllib.quote(self._sourceText)
+ if self._baseUrl != "":
+ retString += "&baseUrl=" + urllib.quote(self._baseUrl)
+ if self._cQuery != "":
+ retString += "&cquery=" + urllib.quote(self._cQuery)
+ if self._xPath != "":
+ retString += "&xpath=" + urllib.quote(self._xPath)
+ return retString
+
+
+class AlchemyAPI_LanguageParams(AlchemyAPI_Params):
+ _sourceText = ""
+ _cQuery = ""
+ _xPath = ""
+ def getSourceText(self):
+ return self._sourceText
+ def setSourceText(self, setting):
+ if setting != 'cleaned_or_raw':
+ if setting != 'cleaned':
+ if setting != 'raw':
+ if setting != 'cquery':
+ if setting != 'xpath':
+ raise Exception, 'Error setting SourceText.'
+ self._sourceText = setting
+ def getConstraintQuery(self):
+ return self._cQuery
+ def setConstraintQuery(self, setting):
+ self._cQuery = setting
+ def getXPath(self):
+ return self._xPath
+ def setXPath(self, setting):
+ self._xPath = setting
+ def getParameterString(self):
+ retString = super(AlchemyAPI_LanguageParams, self).getParameterString()
+ if self._sourceText != "":
+ retString += "&sourceText=" + urllib.quote(self._sourceText)
+ if self._cQuery != "":
+ retString += "&cquery=" + urllib.quote(self._cQuery)
+ if self._xPath != "":
+ retString += "&xpath=" + urllib.quote(self._xPath)
+ return retString
+
+
+class AlchemyAPI_ConceptParams(AlchemyAPI_Params):
+ _sourceText = ""
+ _showSourceText = ""
+ _maxRetrieve = ""
+ _cQuery = ""
+ _xPath = ""
+ _linkedData = ""
+ def getSourceText(self):
+ return self._sourceText
+ def setSourceText(self, setting):
+ if setting != 'cleaned_or_raw':
+ if setting != 'cquery':
+ if setting != 'xpath':
+ raise Exception, 'Error setting SourceText.'
+ self._sourceText = setting
+ def getShowSourceText(self):
+ return self._showSourceText
+ def setShowSourceText(self, setting):
+ if setting != 1:
+ if setting != 0:
+ raise Exception, 'Error setting ShowSourceText.'
+ self._showSourceText = setting
+ def getMaxRetrieve(self):
+ return self._maxRetrieve
+ def setMaxRetrieve(self, setting):
+ self._maxRetrieve = setting
+ def getLinkedData(self):
+ return self._linkedData
+ def setLinkedData(self, setting):
+ if setting != 1:
+ if setting != 0:
+ raise Exception, 'Error setting LinkedData.'
+ self._linkedData = setting
+ def getConstraintQuery(self):
+ return self._cQuery
+ def setConstraintQuery(self, setting):
+ self._cQuery = setting
+ def getXPath(self):
+ return self._xPath
+ def setXPath(self, setting):
+ self._xPath = setting
+ def getParameterString(self):
+ retString = super(AlchemyAPI_ConceptParams, self).getParameterString()
+ if self._sourceText != "":
+ retString += "&sourceText=" + urllib.quote(self._sourceText)
+ if self._showSourceText != "":
+ retString += "&showSourceText=" + str(self._showSourceText)
+ if self._maxRetrieve != "":
+ retString += "&maxRetrieve=" + str(self._maxRetrieve)
+ if self._linkedData != "":
+ retString += "&linkedData=" + str(self._linkedData)
+ if self._cQuery != "":
+ retString += "&cquery=" + urllib.quote(self._cQuery)
+ if self._xPath != "":
+ retString += "&xpath=" + urllib.quote(self._xPath)
+ return retString
+
+
+class AlchemyAPI_KeywordParams(AlchemyAPI_Params):
+ _sourceText = ""
+ _showSourceText = ""
+ _sentiment = ""
+ _maxRetrieve = ""
+ _baseUrl = ""
+ _cQuery = ""
+ _xPath = ""
+ _keywordExtractMode = ""
+ def getSourceText(self):
+ return self._sourceText
+ def setSourceText(self, setting):
+ if setting != 'cleaned_or_raw':
+ if setting != 'cquery':
+ if setting != 'xpath':
+ raise Exception, 'Error setting SourceText.'
+ self._sourceText = setting
+ def getShowSourceText(self):
+ return self._showSourceText
+ def setShowSourceText(self, setting):
+ if setting != 1:
+ if setting != 0:
+ raise Exception, 'Error setting ShowSourceText.'
+ self._showSourceText = setting
+ def getSentiment(self):
+ return self._sentiment
+ def setSentiment(self, setting):
+ if setting != 1:
+ if setting != 0:
+ raise Exception, 'Error setting Sentiment.'
+ self._sentiment = setting
+ def getMaxRetrieve(self):
+ return self._maxRetrieve
+ def setMaxRetrieve(self, setting):
+ self._maxRetrieve = setting
+ def getBaseUrl(self):
+ return self._baseUrl
+ def setBaseUrl(self, setting):
+ self._baseUrl = setting
+ def getConstraintQuery(self):
+ return self._cQuery
+ def setConstraintQuery(self, setting):
+ self._cQuery = setting
+ def getXPath(self):
+ return self._xPath
+ def setXPath(self, setting):
+ self._xPath = setting
+ def getKeywordExtractMode(self):
+ return self._keywordExtractMode
+ def setKeywordExtractMode(self, setting):
+ if setting != 'strict':
+ if setting != 'normal':
+ if setting != '':
+ raise Exception, 'Error setting KeywordExtractMode.'
+ self._keywordExtractMode = setting
+ def getParameterString(self):
+ retString = super(AlchemyAPI_KeywordParams, self).getParameterString()
+ if self._sourceText != "":
+ retString += "&sourceText=" + urllib.quote(self._sourceText)
+ if self._showSourceText != "":
+ retString += "&showSourceText=" + str(self._showSourceText)
+ if self._maxRetrieve != "":
+ retString += "&maxRetrieve=" + str(self._maxRetrieve)
+ if self._baseUrl != "":
+ retString += "&baseUrl=" + urllib.quote(self._baseUrl)
+ if self._cQuery != "":
+ retString += "&cquery=" + urllib.quote(self._cQuery)
+ if self._xPath != "":
+ retString += "&xpath=" + urllib.quote(self._xPath)
+ if self._keywordExtractMode != "":
+ retString += "&keywordExtractMode=" + urllib.quote(self._keywordExtractMode)
+ if self._sentiment != "":
+ retString += "&sentiment=" + str(self._sentiment)
+ return retString
+
+
+class AlchemyAPI_RelationParams(AlchemyAPI_Params):
+ _disambiguate = ""
+ _linkedData = ""
+ _coreference = ""
+ _entities = ""
+ _sentimentExcludeEntities = ""
+ _requireEntities = ""
+ _sourceText = ""
+ _showSourceText = ""
+ _maxRetrieve = ""
+ _baseUrl = ""
+ _cQuery = ""
+ _xPath = ""
+ _sentiment = ""
+ def getDisambiguate(self):
+ return self._disambiguate
+ def setDisambiguate(self, setting):
+ if setting != 1:
+ if setting != 0:
+ raise Exception, 'Error setting Disambiguate.'
+ self._disambiguate = setting
+ def getLinkedData(self):
+ return self._linkedData
+ def setLinkedData(self, setting):
+ if setting != 1:
+ if setting != 0:
+ raise Exception, 'Error setting LinkedData.'
+ self._linkedData = setting
+ def getCoreference(self):
+ return self._coreference
+ def setCoreference(self, setting):
+ if setting != 1:
+ if setting != 0:
+ raise Exception, 'Error setting Coreference.'
+ self._coreference = setting
+ def getEntities(self):
+ return self._entities
+ def setEntities(self, setting):
+ if setting != 1:
+ if setting != 0:
+ raise Exception, 'Error setting Entities.'
+ self._entities = setting
+ def getSentimentExcludeEntities(self):
+ return self._sentimentExcludeEntities
+ def setSentimentExcludeEntities(self, setting):
+ if setting != 1:
+ if setting != 0:
+ raise Exception, 'Error setting SentimentExcludeEntities.'
+ self._sentimentExcludeEntities = setting
+ def getRequireEntities(self):
+ return self._requireEntities
+ def setRequireEntities(self, setting):
+ if setting != 1:
+ if setting != 0:
+ raise Exception, 'Error setting RequireEntities.'
+ self._requireEntities = setting
+ def getShowSourceText(self):
+ return self._showSourceText
+ def setShowSourceText(self, setting):
+ if setting != 1:
+ if setting != 0:
+ raise Exception, 'Error setting ShowSourceText.'
+ self._showSourceText = setting
+ def getSourceText(self):
+ return self._quotations
+ def setSourceText(self, setting):
+ if setting != 'cleaned_or_raw':
+ if setting != 'cleaned':
+ if setting != 'raw':
+ if setting != 'cquery':
+ if setting != 'xpath':
+ raise Exception, 'Error setting SourceText.'
+ self._sourceText = setting
+ def getMaxRetrieve(self):
+ return self._maxRetrieve
+ def setMaxRetrieve(self, setting):
+ self._maxRetrieve = setting
+ def getBaseUrl(self):
+ return self._baseUrl
+ def setBaseUrl(self, setting):
+ self._baseUrl = setting
+ def getConstraintQuery(self):
+ return self._cQuery
+ def setConstraintQuery(self, setting):
+ self._cQuery = setting
+ def getXPath(self):
+ return self._xPath
+ def setXPath(self, setting):
+ self._xPath = setting
+ def getSentiment(self):
+ return self._sentiment
+ def setSentiment(self, setting):
+ if setting != 1:
+ if setting != 0:
+ raise Exception, 'Error setting Sentiment.'
+ self._sentiment = setting
+ def getParameterString(self):
+ retString = super(AlchemyAPI_RelationParams, self).getParameterString()
+ if self._disambiguate != "":
+ retString += "&disambiguate=" + str(self._disambiguate)
+ if self._linkedData != "":
+ retString += "&linkedData=" + str(self._linkedData)
+ if self._coreference != "":
+ retString += "&coreference=" + str(self._coreference)
+ if self._entities != "":
+ retString += "&entities=" + str(self._entities)
+ if self._sentimentExcludeEntities != "":
+ retString += "&sentimentExcludeEntities=" + str(self._sentimentExcludeEntities)
+ if self._requireEntities != "":
+ retString += "&requireEntities=" + str(self._requireEntities)
+ if self._sourceText != "":
+ retString += "&sourceText=" + urllib.quote(self._sourceText)
+ if self._showSourceText != "":
+ retString += "&showSourceText=" + str(self._showSourceText)
+ if self._maxRetrieve != "":
+ retString += "&maxRetrieve=" + str(self._maxRetrieve)
+ if self._baseUrl != "":
+ retString += "&baseUrl=" + urllib.quote(self._baseUrl)
+ if self._cQuery != "":
+ retString += "&cquery=" + urllib.quote(self._cQuery)
+ if self._xPath != "":
+ retString += "&xpath=" + urllib.quote(self._xPath)
+ if self._sentiment != "":
+ retString += "&sentiment=" + str(self._sentiment)
+ return retString
+
+class AlchemyAPI_TextParams(AlchemyAPI_Params):
+ _useMetaData = ""
+ _extractLinks = ""
+ def getUseMetaData(self):
+ return self._useMetaData
+ def setUseMetaData(self, setting):
+ if setting != 1:
+ if setting != 0:
+ raise Exception, 'Error setting UseMetaData.'
+ self._useMetaData = setting
+ def getExtractLinks(self):
+ return self._extractLinks
+ def setExtractLinks(self, setting):
+ if setting != 1:
+ if setting != 0:
+ raise Exception, 'Error setting ExtractLinks.'
+ self._extractLinks = setting
+ def getParameterString(self):
+ retString = super(AlchemyAPI_TextParams, self).getParameterString()
+ if self._useMetaData != "":
+ retString += "&useMetaData=" + str(self._useMetaData)
+ if self._extractLinks != "":
+ retString += "&extractLinks=" + str(self._extractLinks)
+ return retString
+
+
+class AlchemyAPI_ConstraintQueryParams(AlchemyAPI_Params):
+ _cQuery = ""
+ def getConstraintQuery(self):
+ return self._cQuery
+ def setConstraintQuery(self, setting):
+ self._cQuery = setting
+ def getParameterString(self):
+ retString = super(AlchemyAPI_ConstraintQueryParams, self).getParameterString()
+ if self._cQuery != "":
+ retString += "&cquery=" + urllib.quote(self._cQuery)
+ return retString
+
+class AlchemyAPI_TargetedSentimentParams(AlchemyAPI_Params):
+ _showSourceText = ""
+ _target = ""
+ def getShowSourceText(self):
+ return self._showSourceText
+ def setShowSourceText(self, setting):
+ if setting != 1:
+ if setting != 0:
+ raise Exception, 'Error setting showSourceText.'
+ self._showSourceText = setting
+ def getTarget(self):
+ return self._target
+ def setTarget(self, setting):
+ self._target = setting
+ def getParameterString(self):
+ retString = super(AlchemyAPI_TargetedSentimentParams, self).getParameterString()
+ if self._showSourceText != "":
+ retString += "&showSourceText=" + str(self._showSourceText)
+ if self._target != "":
+ retString += "&target=" + str(self._target)
+ return retString
+
+class AlchemyAPI:
+ _apiKey = ""
+ _hostPrefix = "access"
+ def setAPIHost(self, apiHost):
+ self._hostPrefix = apiHost;
+ if len(self._hostPrefix) < 2:
+ raise Exception, 'Error setting API host.'
+ def setAPIKey(self, apiKey):
+ self._apiKey = apiKey;
+ if len(self._apiKey) < 5:
+ raise Exception, 'Error setting API key.'
+ def loadAPIKey(self, filename):
+ file = open(filename, 'r')
+ line = file.readline()
+ self._apiKey = line.strip();
+ if len(self._apiKey) < 5:
+ raise Exception, 'Error loading API key.'
+ def URLGetRankedNamedEntities(self, url, namedEntityParams=None):
+ self.CheckURL(url)
+ if namedEntityParams == None:
+ namedEntityParams = AlchemyAPI_NamedEntityParams()
+ namedEntityParams.setUrl(url)
+ return self.GetRequest("URLGetRankedNamedEntities", "url", namedEntityParams)
+ def HTMLGetRankedNamedEntities(self, html, url, namedEntityParams=None):
+ self.CheckHTML(html, url)
+ if namedEntityParams == None:
+ namedEntityParams = AlchemyAPI_NamedEntityParams()
+ namedEntityParams.setUrl(url)
+ namedEntityParams.setHtml(html)
+ return self.PostRequest("HTMLGetRankedNamedEntities", "html", namedEntityParams)
+ def TextGetRankedNamedEntities(self, text, namedEntityParams=None):
+ self.CheckText(text)
+ if namedEntityParams == None:
+ namedEntityParams = AlchemyAPI_NamedEntityParams()
+ namedEntityParams.setText(text)
+ return self.PostRequest("TextGetRankedNamedEntities", "text", namedEntityParams)
+ def URLGetRankedConcepts(self, url, conceptParams=None):
+ self.CheckURL(url)
+ if conceptParams == None:
+ conceptParams = AlchemyAPI_ConceptParams()
+ conceptParams.setUrl(url)
+ return self.GetRequest("URLGetRankedConcepts", "url", conceptParams)
+ def HTMLGetRankedConcepts(self, html, url, conceptParams=None):
+ self.CheckHTML(html, url)
+ if conceptParams == None:
+ conceptParams = AlchemyAPI_ConceptParams()
+ conceptParams.setUrl(url)
+ conceptParams.setHtml(html)
+ return self.PostRequest("HTMLGetRankedConcepts", "html", conceptParams)
+ def TextGetRankedConcepts(self, text, conceptParams=None):
+ self.CheckText(text)
+ if conceptParams == None:
+ conceptParams = AlchemyAPI_ConceptParams()
+ conceptParams.setText(text)
+ return self.PostRequest("TextGetRankedConcepts", "text", conceptParams)
+ def URLGetRankedKeywords(self, url, keywordParams=None):
+ self.CheckURL(url)
+ if keywordParams == None:
+ keywordParams = AlchemyAPI_KeywordParams()
+ keywordParams.setUrl(url)
+ return self.GetRequest("URLGetRankedKeywords", "url", keywordParams)
+ def HTMLGetRankedKeywords(self, html, url, keywordParams=None):
+ self.CheckHTML(html, url)
+ if keywordParams == None:
+ keywordParams = AlchemyAPI_KeywordParams()
+ keywordParams.setUrl(url)
+ keywordParams.setHtml(html)
+ return self.PostRequest("HTMLGetRankedKeywords", "html", keywordParams)
+ def TextGetRankedKeywords(self, text, keywordParams=None):
+ self.CheckText(text)
+ if keywordParams == None:
+ keywordParams = AlchemyAPI_KeywordParams()
+ keywordParams.setText(text)
+ return self.PostRequest("TextGetRankedKeywords", "text", keywordParams)
+ def URLGetLanguage(self, url, languageParams=None):
+ self.CheckURL(url)
+ if languageParams == None:
+ languageParams = AlchemyAPI_LanguageParams()
+ languageParams.setUrl(url)
+ return self.GetRequest("URLGetLanguage", "url", languageParams)
+ def HTMLGetLanguage(self, html, url, languageParams=None):
+ self.CheckHTML(html, url)
+ if languageParams == None:
+ languageParams = AlchemyAPI_LanguageParams()
+ languageParams.setUrl(url)
+ languageParams.setHtml(html)
+ return self.PostRequest("HTMLGetLanguage", "html", languageParams)
+ def TextGetLanguage(self, text, languageParams=None):
+ self.CheckText(text)
+ if languageParams == None:
+ languageParams = AlchemyAPI_LanguageParams()
+ languageParams.setText(text)
+ return self.PostRequest("TextGetLanguage", "text", languageParams)
+ def URLGetCategory(self, url, categParams=None):
+ self.CheckURL(url)
+ if categParams == None:
+ categParams = AlchemyAPI_CategoryParams()
+ categParams.setUrl(url)
+ return self.GetRequest("URLGetCategory", "url", categParams)
+ def HTMLGetCategory(self, html, url, categParams=None):
+ self.CheckHTML(html, url)
+ if categParams == None:
+ categParams = AlchemyAPI_CategoryParams()
+ categParams.setUrl(url)
+ categParams.setHtml(html)
+ return self.PostRequest("HTMLGetCategory", "html", categParams)
+ def TextGetCategory(self, text, categParams=None):
+ self.CheckText(text)
+ if categParams == None:
+ categParams = AlchemyAPI_CategoryParams()
+ categParams.setText(text)
+ return self.PostRequest("TextGetCategory", "text", categParams)
+ def URLGetText(self, url, textParams=None):
+ self.CheckURL(url)
+ if textParams == None:
+ textParams = AlchemyAPI_TextParams()
+ textParams.setUrl(url)
+ return self.GetRequest("URLGetText", "url", textParams)
+ def HTMLGetText(self, html, url, textParams=None):
+ self.CheckHTML(html, url)
+ if textParams == None:
+ textParams = AlchemyAPI_TextParams()
+ textParams.setUrl(url)
+ textParams.setHtml(html)
+ return self.PostRequest("HTMLGetText", "html", textParams)
+ def URLGetRawText(self, url, baseParams=None):
+ self.CheckURL(url)
+ if baseParams == None:
+ baseParams = AlchemyAPI_Params()
+ baseParams.setUrl(url)
+ return self.GetRequest("URLGetRawText", "url", baseParams)
+ def HTMLGetRawText(self, html, url, baseParams=None):
+ self.CheckHTML(html, url)
+ if baseParams == None:
+ baseParams = AlchemyAPI_Params()
+ baseParams.setUrl(url)
+ baseParams.setHtml(html)
+ return self.PostRequest("HTMLGetRawText", "html", baseParams)
+ def URLGetTitle(self, url, baseParams=None):
+ self.CheckURL(url)
+ if baseParams == None:
+ baseParams = AlchemyAPI_Params()
+ baseParams.setUrl(url)
+ return self.GetRequest("URLGetTitle", "url", baseParams)
+ def HTMLGetTitle(self, html, url, baseParams=None):
+ self.CheckHTML(html, url)
+ if baseParams == None:
+ baseParams = AlchemyAPI_Params()
+ baseParams.setUrl(url)
+ baseParams.setHtml(html)
+ return self.PostRequest("HTMLGetTitle", "html", baseParams)
+ def URLGetFeedLinks(self, url, baseParams=None):
+ self.CheckURL(url)
+ if baseParams == None:
+ baseParams = AlchemyAPI_Params()
+ baseParams.setUrl(url)
+ return self.GetRequest("URLGetFeedLinks", "url", baseParams)
+ def HTMLGetFeedLinks(self, html, url, baseParams=None):
+ self.CheckHTML(html, url)
+ if baseParams == None:
+ baseParams = AlchemyAPI_Params()
+ baseParams.setUrl(url)
+ baseParams.setHtml(html)
+ return self.PostRequest("HTMLGetFeedLinks", "html", baseParams)
+ def URLGetMicroformats(self, url, baseParams=None):
+ self.CheckURL(url)
+ if baseParams == None:
+ baseParams = AlchemyAPI_Params()
+ baseParams.setUrl(url)
+ return self.GetRequest("URLGetMicroformatData", "url", baseParams)
+ def HTMLGetMicroformats(self, html, url, baseParams=None):
+ self.CheckHTML(html, url)
+ if baseParams == None:
+ baseParams = AlchemyAPI_Params()
+ baseParams.setUrl(url)
+ baseParams.setHtml(html)
+ return self.PostRequest("HTMLGetMicroformatData", "html", baseParams)
+ def URLGetConstraintQuery(self, url, query, cQueryParams=None):
+ self.CheckURL(url)
+ if len(query) < 2:
+ raise Exception, 'Invalid constraint query specified.'
+ if cQueryParams == None:
+ cQueryParams = AlchemyAPI_ConstraintQueryParams()
+ cQueryParams.setUrl(url)
+ cQueryParams.setConstraintQuery(query)
+ return self.GetRequest("URLGetConstraintQuery", "url", cQueryParams)
+ def HTMLGetConstraintQuery(self, html, url, query, cQueryParams=None):
+ self.CheckHTML(html, url)
+ if len(query) < 2:
+ raise Exception, 'Invalid constraint query specified.'
+ if cQueryParams == None:
+ cQueryParams = AlchemyAPI_ConstraintQueryParams()
+ cQueryParams.setUrl(url)
+ cQueryParams.setHtml(html)
+ cQueryParams.setConstraintQuery(query)
+ return self.PostRequest("HTMLGetConstraintQuery", "html", cQueryParams)
+ def URLGetTextSentiment(self, url, baseParams=None):
+ self.CheckURL(url)
+ if baseParams == None:
+ baseParams = AlchemyAPI_Params()
+ baseParams.setUrl(url)
+ return self.GetRequest("URLGetTextSentiment", "url", baseParams)
+ def HTMLGetTextSentiment(self, html, url, baseParams=None):
+ self.CheckHTML(html, url)
+ if baseParams == None:
+ baseParams = AlchemyAPI_Params()
+ baseParams.setUrl(url)
+ baseParams.setHtml(html)
+ return self.PostRequest("HTMLGetTextSentiment", "html", baseParams)
+ def TextGetTextSentiment(self, text, baseParams=None):
+ self.CheckText(text)
+ if baseParams == None:
+ baseParams = AlchemyAPI_Params()
+ baseParams.setText(text)
+ return self.PostRequest("TextGetTextSentiment", "text", baseParams)
+ def URLGetTargetedSentiment(self, url, target, targetedSentimentParams=None):
+ self.CheckURL(url)
+ if targetedSentimentParams == None:
+ targetedSentimentParams = AlchemyAPI_TargetedSentimentParams()
+ targetedSentimentParams.setUrl(url)
+ targetedSentimentParams.setTarget(target)
+ return self.GetRequest("URLGetTargetedSentiment", "url", targetedSentimentParams)
+ def HTMLGetTargetedSentiment(self, html, url, target, targetedSentimentParams=None):
+ self.CheckHTML(html, url)
+ if targetedSentimentParams == None:
+ targetedSentimentParams = AlchemyAPI_TargetedSentimentParams()
+ targetedSentimentParams.setUrl(url)
+ targetedSentimentParams.setHtml(html)
+ targetedSentimentParams.setTarget(target)
+ return self.PostRequest("HTMLGetTargetedSentiment", "html", targetedSentimentParams)
+ def TextGetTargetedSentiment(self, text, target, targetedSentimentParams=None):
+ self.CheckText(text)
+ if targetedSentimentParams == None:
+ targetedSentimentParams = AlchemyAPI_TargetedSentimentParams()
+ targetedSentimentParams.setText(text)
+ targetedSentimentParams.setTarget(target)
+ return self.PostRequest("TextGetTargetedSentiment", "text", targetedSentimentParams)
+ def URLGetRelations(self, url, relationParams=None):
+ self.CheckURL(url)
+ if relationParams == None:
+ relationParams = AlchemyAPI_RelationParams()
+ relationParams.setUrl(url)
+ return self.GetRequest("URLGetRelations", "url", relationParams)
+ def HTMLGetRelations(self, html, url, relationParams=None):
+ self.CheckHTML(html, url)
+ if relationParams == None:
+ relationParams = AlchemyAPI_RelationParams()
+ relationParams.setUrl(url)
+ relationParams.setHtml(html)
+ return self.PostRequest("HTMLGetRelations", "html", relationParams)
+ def TextGetRelations(self, text, relationParams=None):
+ self.CheckText(text)
+ if relationParams == None:
+ relationParams = AlchemyAPI_RelationParams()
+ relationParams.setText(text)
+ return self.PostRequest("TextGetRelations", "text", relationParams)
+ def URLGetAuthor(self, url, baseParams=None):
+ self.CheckURL(url)
+ if baseParams == None:
+ baseParams = AlchemyAPI_Params()
+ baseParams.setUrl(url)
+ return self.GetRequest("URLGetAuthor", "url", baseParams)
+ def HTMLGetAuthor(self, html, url, baseParams=None):
+ self.CheckHTML(html, url)
+ if baseParams == None:
+ baseParams = AlchemyAPI_Params()
+ baseParams.setUrl(url)
+ baseParams.setHtml(html)
+ return self.PostRequest("HTMLGetAuthor", "html", baseParams)
+ def CheckText(self, text):
+ if len(self._apiKey) < 5:
+ raise Exception, 'Please load an API key.'
+ if len(text) < 5:
+ raise Exception, 'Please specify some text to analyze.'
+ def CheckHTML(self, html, url):
+ if len(self._apiKey) < 5:
+ raise Exception, 'Please load an API key.'
+ if len(html) < 10:
+ raise Exception, 'Please specify a HTML document to analyze.'
+ if len(url) < 10:
+ raise Exception, 'Please specify a URL to analyze.'
+ def CheckURL(self, url):
+ if len(self._apiKey) < 5:
+ raise Exception, 'Please load an API key.'
+ if len(url) < 10:
+ raise Exception, 'Please specify a URL to analyze.'
+ def PostRequest(self, apiCall, apiPrefix, paramObject):
+ endpoint = 'http://' + self._hostPrefix + '.alchemyapi.com/calls/' + apiPrefix + '/' + apiCall
+ argText = 'apikey=' + self._apiKey + paramObject.getParameterString()
+ handle = urllib.urlopen(endpoint, argText)
+ result = handle.read()
+ handle.close()
+ xpathQuery = './/status'
+ nodes = etree.fromstring(result).find(xpathQuery)
+ if nodes.text != "OK":
+ raise Exception, 'Error making API call.'
+ return result
+ def GetRequest(self, apiCall, apiPrefix, paramObject):
+ endpoint = 'http://' + self._hostPrefix + '.alchemyapi.com/calls/' + apiPrefix + '/' + apiCall
+ endpoint += '?apikey=' + self._apiKey + paramObject.getParameterString()
+ handle = urllib.urlopen(endpoint)
+ result = handle.read()
+ handle.close()
+
+ mode = paramObject.getOutputMode()
+ if mode == "json":
+
+ return json.loads( result )
+
+ xpathQuery = './/status'
+ nodes = etree.fromstring(result).find(xpathQuery)
+ if nodes.text != "OK":
+ raise Exception, 'Error making API call.'
+ return result
10 glue/admin.py
View
@@ -1,5 +1,11 @@
from django.contrib import admin
-from glue.models import Page, Pin
+from glue.models import Page, Pin, Tag
+
+
+class TagAdmin(admin.ModelAdmin):
+ search_fields = ['name']
+
admin.site.register( Page )
-admin.site.register( Pin )
+admin.site.register( Pin )
+admin.site.register( Tag, TagAdmin )
138 glue/api.py
View
@@ -8,7 +8,7 @@
from django.template.defaultfilters import slugify
from glue import Epoxy, API_EXCEPTION_FORMERRORS, API_EXCEPTION_INTEGRITY, API_EXCEPTION_DOESNOTEXIST, API_EXCEPTION_OSERROR
-from glue.models import Page, Pin
+from glue.models import Page, Pin, Tag
from glue.forms import AddPageForm, AddPinForm, EditPinForm, UploadPinForm
@@ -68,53 +68,57 @@ def pins( request ):
if not form.is_valid():
return response.throw_error( error=form.errors, code=API_EXCEPTION_FORMERRORS).json()
+ pages = {}
+
if len(form.cleaned_data['page_slug']) > 0:
# attacch new pin to a selected page (both languages)
response.add('page_slug',form.cleaned_data['page_slug'])
- try:
- page_en = Page.objects.get( slug=form.cleaned_data['page_slug'],language='EN')
- page_fr = Page.objects.get( slug=form.cleaned_data['page_slug'],language='FR')
- except Page.DoesNotExist:
- return response.throw_error( error=_("selected page does not exists"), code=API_EXCEPTION_FORMERRORS).json()
+
+ for language,l in settings.LANGUAGES:
+ try:
+ pages[ language ] = Page.objects.get( slug=form.cleaned_data['page_slug'], language=language )
+ except Page.DoesNotExist:
+ return response.throw_error( error=_("selected page does not exists"), code=API_EXCEPTION_FORMERRORS ).json()
+
+ response.add('pages', [ pages[p].json() for p in pages ] )
- response.add('page', [ page_en.json(), page_fr.json() ] )
+ pins = {}
if len(form.cleaned_data['parent_pin_slug']) > 0:
+
# attacch new pin to a selected pin (pin children, usually displayed on the right side, both languages)
response.add('parent_pin_slug',form.cleaned_data['parent_pin_slug'])
- try:
- pin_en = Pin.objects.get( slug=form.cleaned_data['parent_pin_slug'],language='EN')
- pin_fr = Pin.objects.get( slug=form.cleaned_data['parent_pin_slug'],language='FR')
- except Pin.DoesNotExist, e:
- return response.throw_error( error=_("selected pin does not exists. Exception: %s" % e), code=API_EXCEPTION_FORMERRORS).json()
+
+ for language,l in settings.LANGUAGES:
+ try:
+ pins[ language ] = Pin.objects.get( slug=form.cleaned_data['parent_pin_slug'], language=language )
+ except Pin.DoesNotExist, e:
+ return response.throw_error( error=_("selected pin does not exists. Exception: %s" % e), code=API_EXCEPTION_FORMERRORS).json()
- response.add('pin', [ pin_en.json(), pin_fr.json() ] )
+ response.add('pins', [ pins[p].json() for p in pins ] )
#return response.queryset( Pin.objects.filter() ).json()
+ ipins = {}
- try:
- p_en = Pin( title=form.cleaned_data['title_en'], language='EN', slug=form.cleaned_data['slug'])
- p_fr = Pin( title=form.cleaned_data['title_fr'], language='FR', slug=form.cleaned_data['slug'])
-
- if len(form.cleaned_data['parent_pin_slug']) > 0:
- p_en.parent = pin_en
- p_fr.parent = pin_fr
+ for language,l in settings.LANGUAGES:
+ try:
+ ipin = Pin( title=form.cleaned_data[ 'title_%s' % language ], language=language, slug=form.cleaned_data[ 'slug' ], permalink=form.cleaned_data['permalink'] )
+ ipin.save()
-
- p_en.save()
- p_fr.save()
- except IntegrityError, e:
- return response.throw_error( error={'slug':"Exception %s" % e}, code=API_EXCEPTION_INTEGRITY).json()
+ except IntegrityError, e:
+ return response.throw_error( error={'slug':"Exception %s" % e}, code=API_EXCEPTION_INTEGRITY).json()
- if len(form.cleaned_data['page_slug']) > 0:
- page_en.pins.add( p_en )
- page_en.save()
- page_fr.pins.add( p_fr )
- page_fr.save()
+ if len(pages) > 0:
+ pages[ language ].pins.add( ipin )
+ pages[ language ].save()
- response.add('object',[ p_en.json(), p_fr.json() ])
+ if len(pins) > 0:
+ ipin.parent = pins[ language ]
+ ipin.save()
+
+ response.add('object',[ p.json() for p in ipins ])
return response.queryset( Pin.objects.filter() ).json()
@@ -145,9 +149,63 @@ def pin( request, pin_id ):
return response.single( Pin, {'id':pin_id} ).json()
+
+
def pin_by_slug( request, pin_slug, pin_language ):
return Epoxy( request ).single( Pin, {'slug':pin_slug,'language':pin_language} ).json()
+def pin_by_parmalink( request ):
+
+ return Epoxy( request ).single( Pin, {'slug':pin_slug,'language':pin_language} ).json()
+
+def pin_alchemy( request, pin_id ):
+ response = Epoxy( request )
+
+ try:
+ pin = Pin.objects.get( id=pin_id )
+ except Pin.DoesNotExist, e:
+ return response.throw_error( error="%s" % e, code=API_EXCEPTION_DOESNOTEXIST).json()
+
+ # check alchemy availability
+ from glue import AlchemyAPI
+
+ ao = AlchemyAPI.AlchemyAPI()
+
+ try:
+ ao.setAPIKey( settings.ALCHEMY_API_KEY )
+ except AttributeError, e:
+ return response.throw_error( error="You didn't specify an AlchemyAPI key", code=API_EXCEPTION_DOESNOTEXIST).json()
+
+ # Has it alchemy tags already?
+ if len( pin.permalink) > 0 :
+
+ # if len( pin.permalink > 0) :
+ result = response.add( "URLGetTitle", ao.URLGetTitle( pin.permalink ) );
+ result = response.add( "URLGetRankedNamedEntities", ao.URLGetRankedNamedEntities( pin.permalink ) );
+ result = response.add( "URLGetRankedConcepts", ao.URLGetRankedConcepts( pin.permalink ) );
+
+
+ #except Exception, e:
+ # return response.throw_error( error="%s" % e, code=API_EXCEPTION_OSERROR ).json()
+ return response.json();
+
+
+def pin_tags( request, pin_id ):
+ response = Epoxy( request )
+ # get pins
+ try:
+ pins = Pin.objects.get( id=pin_id )
+ except Pin.DoesNotExist, e:
+ return response.throw_error( error="%s" % e, code=API_EXCEPTION_DOESNOTEXIST).json()
+
+ if response.method == 'POST':
+ form = AddTagForm( request.REQUEST )
+ if not form.is_valid():
+ return response.throw_error( error=form.errors, code=API_EXCEPTION_FORMERRORS ).json()
+
+
+ return response.queryset( Tag.objects.filter( pin__id=pin_id) ).json()
+
def publish_pin( request, pin_id ):
response = Epoxy( request )
new_status = request.POST.get("new_status")
@@ -163,7 +221,23 @@ def publish_pin( request, pin_id ):
except Pin.DoesNotExist, e:
return response.throw_error( error="%s" % e, code=API_EXCEPTION_DOESNOTEXIST).json()
-
+
+def pin_clean( request, pin_id ):
+ import re
+ response = Epoxy( request )
+
+ try:
+ pin = Page.objects.get( id = pin_id )
+ except Pin.DoesNotExist, e:
+ return response.throw_error( error="%s" % e, code=API_EXCEPTION_DOESNOTEXIST).json()
+
+ e = re.compile( r'<span *[^>]*>(.*)</span *>')
+ pin.content = e.sub( r"\1", pin.content )
+ pin.save()
+
+ response.add( 'object', pin, jsonify=True)
+
+ return response.json()
def pin_upload( request ):
response = Epoxy( request )
32 glue/forms.py
View
@@ -1,6 +1,8 @@
from django import forms
from django.forms import ModelForm
from django.utils.translation import ugettext as _
+from django.conf import settings
+from glue.models import Tag
class LoginForm(forms.Form):
username = forms.CharField( label=_('login'), max_length=64 )
@@ -8,14 +10,29 @@ class LoginForm(forms.Form):
class AddPageForm(forms.Form):
- title_fr = forms.CharField( label=_("french title"),required=True )
- title_en = forms.CharField( label=_("english title"), required=True )
+ def __init__(self, *args, **kwargs):
+
+ super(AddPageForm, self).__init__(*args, **kwargs)
+
+ for l,lang in settings.LANGUAGES:
+ self.fields['title_%s' % l] = forms.CharField( label=_("%s title" % lang), required=True )
+
slug = forms.SlugField( required=True )
+
+
class AddPinForm(forms.Form):
- title_fr = forms.CharField( label=_("french title"),required=True )
- title_en = forms.CharField( label=_("english title"), required=True )
+
+ def __init__(self, *args, **kwargs):
+
+ super(AddPinForm, self).__init__(*args, **kwargs)
+
+ for l,lang in settings.LANGUAGES:
+ self.fields['title_%s' % l] = forms.CharField( label=_("%s title" % lang), required=True )
+
+
slug = forms.SlugField( required=True )
+ permalink = forms.URLField( required=False )
page_slug = forms.SlugField( required=False, widget=forms.HiddenInput )
parent_pin_slug = forms.SlugField( required=False, widget=forms.HiddenInput )
@@ -26,4 +43,9 @@ class EditPinForm(forms.Form):
class UploadPinForm(forms.Form): # an upload form without file :D (upload via ajax)
page_slug = forms.SlugField( required=False, widget=forms.HiddenInput )
- parent_pin_slug = forms.SlugField( required=False, widget=forms.HiddenInput )
+ parent_pin_slug = forms.SlugField( required=False, widget=forms.HiddenInput )
+
+class AddTagForm(forms.Form):
+ name = forms.CharField( label=_("tag name"),required=True )
+ slug = forms.SlugField( required=True )
+ type = forms.CharField( label=_("type"), required=True, widget = forms.ChoiceField( widget=forms.Select, choices=Tag.TYPE_CHOICES ) )
88 glue/models.py
View
@@ -3,6 +3,57 @@
from django.db import models
+class Serie( models.Model ):
+
+ KEY = "Ke"
+ GHOST = "GH" # a non published serie ?
+ GHOST = "GH"
+
+ TYPE_CHOICES = (
+ (KEY, 'key frame'),
+ (GHOST, 'ghost'),
+ )
+
+ slug = models.SlugField( unique=True )
+ title = models.CharField( max_length=160, default="", blank=True, null=True )
+ abstract = models.TextField( default="", blank=True, null=True )
+ content = models.TextField( default="", blank=True, null=True )
+
+ type = models.CharField( max_length=2, choices=TYPE_CHOICES ) # if true, serie is a default serie
+
+ date = models.DateField( blank=True, null=True ) # main date, manually added
+ date_last_modified = models.DateField( auto_now=True ) # date last save()
+
+
+ frames = models.ManyToManyField( Pin, through='Frame', null=True, blank=True )
+ related = models.ManyToManyField("self", symmetrical=True, null=True, blank=True )
+
+
+
+class Frame( models.Model ):
+
+ KEY = "Ke"
+ GHOST = "GH" # visible but just for reference.
+
+
+ TYPE_CHOICES = (
+ (KEY, 'key frame'),
+ (GHOST, 'ghost'),
+ )
+
+ pin = models.ForeignKey( Pin )
+ serie = models.ForeignKey( Serie )
+ sort = models.IntegerField( default=0 )
+
+ type = models.CharField( max_length=2, choices=TYPE_CHOICES )
+
+ abstract = models.TextField( default="", blank=True, null=True ) # a description of the passage
+
+ class Meta:
+ unique_together = ( "serie", "sort" )
+ ordering = ('sort' )
+
+
class Geo( models.Model): # geo spot, with zoom
lat = models.FloatField() # map center LAT
lon = models.FloatField() # map center LON
@@ -10,7 +61,38 @@ class Geo( models.Model): # geo spot, with zoom
content = models.TextField( default="", blank=True, null=True ) # textual GEO description
# class Tag( models.Model ):
+class Tag(models.Model):
+
+ # feel free to add tag type to this model ... :D
+ AUTHOR = 'Au'
+ KEYWORD = 'Ke'
+ INSTITUTION = 'In'
+ RESEARCHER = 'Rs'
+ PLACE = 'Pl'
+ DATE = 'Da'
+ GEOCOVER = 'GC'
+
+
+ TYPE_CHOICES = (
+ (AUTHOR, 'AUTHOR'),
+ (KEYWORD, 'KEYWORD'),
+ (INSTITUTION, 'Institution'),
+ (RESEARCHER, 'Researcher'),
+ (PLACE, 'Place'),
+ (DATE, 'Date'),
+ (GEOCOVER, 'Geographic coverage')
+ )
+
+ name = models.CharField(max_length=128) # e.g. 'Mr. E. Smith'
+ slug = models.SlugField(max_length=128) # e.g. 'mr-e-smith'
+ type = models.CharField( max_length=2, choices=TYPE_CHOICES ) # e.g. 'author' or 'institution'
+
+ def __unicode__(self):
+ return "%s : %s"% ( self.get_type_display(), self.name)
+ class Meta:
+ ordering = ["type", "slug" ]
+ unique_together = ("type", "slug")
class Pin( models.Model ):
published='P'
@@ -38,11 +120,12 @@ class Pin( models.Model ):
status = models.CharField( max_length=2, default="D",choices=PIN_STATUS_CHOICES)
geos = models.ManyToManyField( Geo, blank=True, null=True ) # add geographic point
+ tags = models.ManyToManyField( Tag, blank=True, null=True ) # add tags !
users = models.ManyToManyField( User, blank=True, null=True )
class Meta:
unique_together = ( "slug", "language" )
- ordering = ('sort','id')
+ ordering = ('sort','-id')
def __unicode__(self):
return "%s (%s) a.k.a. %s" % (self.slug, self.language, self.title)
@@ -59,6 +142,9 @@ def json( self ):
}
+
+
+
class PageAbstract( models.Model ):
slug = models.SlugField()
title = models.CharField( max_length=160, default="", blank=True, null=True )
6 glue/urls.py
View
@@ -15,8 +15,12 @@
url(r'^page/(?P<page_slug>[a-zA-Z\d\-]+)/(?P<page_language>[a-zA-Z]{2})/$', 'glue.api.page_by_slug', name='glue_api_page_by_slug'),
url(r'^pin/$', 'glue.api.pins', name='glue_api_pins'), # get list, post single page
- url(r'^pin/(?P<pin_id>\d+)/$', 'glue.api.pin', name='glue_api_pin'),
+ url(r'^pin/(?P<pin_id>\d+)/$', 'glue.api.pin', name='glue_api_pin'),
+ url(r'^pin/(?P<pin_id>\d+)/tag/$', 'glue.api.pin_tags', name='glue_api_pin_tags'),
+ url(r'^pin/(?P<pin_id>\d+)/alchemy/$', 'glue.api.pin_alchemy', name='glue_api_pin_alchemy'),
url(r'^pin/(?P<pin_slug>[a-zA-Z\d\-]+)/(?P<pin_language>[a-zA-Z]{2})/$', 'glue.api.pin_by_slug', name='glue_api_pin_by_slug'),
url(r'^pin/(?P<pin_id>\d+)/publish/$', 'glue.api.publish_pin', name='glue_api_publish_pin'),
+ url(r'^pin/(?P<pin_id>\d+)/clean/$', 'glue.api.pin_clean', name='glue_api_pin_clean'),
url(r'^pin/upload/$', 'glue.api.pin_upload', name='glue_api_pin_upload'),
+
)
62 requirements.txt
View
@@ -1,3 +1,65 @@
+BeautifulSoup==3.1.0.1
+ClientForm==0.2.10
Django==1.4.5
+Genshi==0.5.1
+MySQL-python==1.2.2
+PAM==0.4.2
+PIL==1.1.7
+Pattern==2.1
+PyYAML==3.09
+Pygments==1.2.2
+SQLAlchemy==0.7.2
+Scrapy==0.14.1
+Scrapyd==0.17.1-11-gb25a896
+Twisted==11.1.0
+Twisted-Conch==10.0.0
+Twisted-Core==10.0.0
+Twisted-Lore==10.0.0
+Twisted-Mail==10.0.0
+Twisted-Names==10.0.0
+Twisted-News==10.0.0
+Twisted-Runner==10.0.0
+Twisted-Web==10.0.0
+Twisted-Words==10.0.0
argparse==1.2.1
+boto==1.9b
+distribute==0.6.10
+django-haystack==1.2.5
+django-tables2==0.7.8
+django-tinymce==1.5.1a2
+foolscap==0.5.1
+geopy==0.94.1
+guppy==0.1.9
+httplib2==0.7.1
+ipython==0.10
+lxml==2.3beta1
+mod-python==3.3.1
+networkx==1.6
+nltk==2.0b8
+pexpect==2.3
+phpserialize==1.2
+psutil==0.3.0
+psycopg2==2.4.2
+pyOpenSSL==0.10
+pyasn1==0.0.8a
+pybtex==0.16
+pycrypto==2.0.1
+pymongo==2.4.2
+pyserial==2.3
+pysolr==2.1.0-beta
+python-apt==0.7.94.2ubuntu6
+python-ptrace==0.6.3
+pythonsolr==1.0
+rainbow==0.8.6
+simplejson==2.2.1
+stevedore==0.8
+thrift==0.8.0
+virtualenv==1.4.5
+virtualenv-clone==0.2.4
+virtualenvwrapper==3.6
+w3lib==1.0
+webcorpus==0.1
wsgiref==0.1.2
+wxPython==2.8.10.1
+wxPython-common==2.8.10.1
+zope.interface==3.5.3
1  static/admin
View
9 static/css/bootstrap.min.css
View
9 additions, 0 deletions not shown
160 static/js/jquery.reveal.js
View
@@ -0,0 +1,160 @@
+/*
+ * jQuery Reveal Plugin 1.0
+ * www.ZURB.com
+ * Copyright 2010, ZURB
+ * Free to use under the MIT license.
+ * http://www.opensource.org/licenses/mit-license.php
+*/
+
+
+(function($) {
+
+/*---------------------------
+ Defaults for Reveal
+----------------------------*/
+
+/*---------------------------
+ Listener for data-reveal-id attributes
+----------------------------*/
+
+ $('a[data-reveal-id]').on('click', function(e) {
+ e.preventDefault();
+ var modalLocation = $(this).attr('data-reveal-id');
+ $('#'+modalLocation).reveal($(this).data());
+ });
+
+/*---------------------------
+ Extend and Execute
+----------------------------*/
+
+ $.fn.reveal = function(options) {
+
+
+ var defaults = {
+ animation: 'fadeAndPop', //fade, fadeAndPop, none
+ animationspeed: 300, //how fast animtions are
+ closeonbackgroundclick: true, //if you click background will modal close?
+ dismissmodalclass: 'close-reveal-modal' //the class of a button or element that will close an open modal
+ };
+
+ //Extend dem' options
+ var options = $.extend({}, defaults, options);
+
+ return this.each(function() {
+
+/*---------------------------
+ Global Variables
+----------------------------*/
+ var modal = $(this),
+ topMeasure = parseInt(modal.css('top')),
+ topOffset = modal.height() + topMeasure,
+ locked = false,
+ modalBG = $('.reveal-modal-bg');
+
+/*---------------------------
+ Create Modal BG
+----------------------------*/
+ if(modalBG.length == 0) {
+ modalBG = $('<div class="reveal-modal-bg" />').insertAfter(modal);
+ }
+
+/*---------------------------
+ Open & Close Animations
+----------------------------*/
+ //Entrance Animations
+ modal.bind('reveal:open', function () {
+ modalBG.unbind('click.modalEvent');
+ $('.' + options.dismissmodalclass).unbind('click.modalEvent');
+ if(!locked) {
+ lockModal();
+ if(options.animation == "fadeAndPop") {
+ modal.css({'top': $(document).scrollTop()-topOffset, 'opacity' : 0, 'visibility' : 'visible'});
+ modalBG.fadeIn(options.animationspeed/2);
+ modal.delay(options.animationspeed/2).animate({
+ "top": $(document).scrollTop()+topMeasure + 'px',
+ "opacity" : 1
+ }, options.animationspeed,unlockModal());
+ }
+ if(options.animation == "fade") {
+ modal.css({'opacity' : 0, 'visibility' : 'visible', 'top': $(document).scrollTop()+topMeasure});
+ modalBG.fadeIn(options.animationspeed/2);
+ modal.delay(options.animationspeed/2).animate({
+ "opacity" : 1
+ }, options.animationspeed,unlockModal());
+ }
+ if(options.animation == "none") {
+ modal.css({'visibility' : 'visible', 'top':$(document).scrollTop()+topMeasure});
+ modalBG.css({"display":"block"});
+ unlockModal()
+ }
+ }
+ modal.unbind('reveal:open');
+ });
+
+ //Closing Animation
+ modal.bind('reveal:close', function () {
+ if(!locked) {
+ lockModal();
+ if(options.animation == "fadeAndPop") {
+ modalBG.delay(options.animationspeed).fadeOut(options.animationspeed);
+ modal.animate({
+ "top": $(document).scrollTop()-topOffset + 'px',
+ "opacity" : 0
+ }, options.animationspeed/2, function() {
+ modal.css({'top':topMeasure, 'opacity' : 1, 'visibility' : 'hidden'});
+ unlockModal();
+ });
+ }
+ if(options.animation == "fade") {
+ modalBG.delay(options.animationspeed).fadeOut(options.animationspeed);
+ modal.animate({
+ "opacity" : 0
+ }, options.animationspeed, function() {
+ modal.css({'opacity' : 1, 'visibility' : 'hidden', 'top' : topMeasure});
+ unlockModal();
+ });
+ }
+ if(options.animation == "none") {
+ modal.css({'visibility' : 'hidden', 'top' : topMeasure});
+ modalBG.css({'display' : 'none'});
+ }
+ }
+ modal.unbind('reveal:close');
+ });
+
+/*---------------------------
+ Open and add Closing Listeners
+----------------------------*/
+ //Open Modal Immediately
+ modal.trigger('reveal:open')
+
+ //Close Modal Listeners
+ var closeButton = $('.' + options.dismissmodalclass).bind('click.modalEvent', function () {
+ modal.trigger('reveal:close')
+ });
+
+ if(options.closeonbackgroundclick) {
+ modalBG.css({"cursor":"pointer"})
+ modalBG.bind('click.modalEvent', function () {
+ modal.trigger('reveal:close')
+ });
+ }
+ $('body').keyup(function(e) {
+ if(e.which===27){ modal.trigger('reveal:close'); } // 27 is the keycode for the Escape key
+ });
+
+
+/*---------------------------
+ Animations Locks
+----------------------------*/
+ function unlockModal() {
+ locked = false;
+ }
+ function lockModal() {
+ locked = true;
+ }
+
+ });//each call
+ }//orbit plugin call
+})(jQuery);
+
172 static/js/jquery.toastmessage.js
View
@@ -0,0 +1,172 @@
+/*
+ * Copyright 2010 akquinet
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * This JQuery Plugin will help you in showing some nice Toast-Message like notification messages. The behavior is
+ * similar to the android Toast class.
+ * You have 4 different toast types you can show. Each type comes with its own icon and colored border. The types are:
+ * - notice
+ * - success
+ * - warning
+ * - error
+ *
+ * The following methods will display a toast message:
+ *
+ * $().toastmessage('showNoticeToast', 'some message here');
+ * $().toastmessage('showSuccessToast', "some message here");
+ * $().toastmessage('showWarningToast', "some message here");
+ * $().toastmessage('showErrorToast', "some message here");
+ *
+ * // user configured toastmessage:
+ * $().toastmessage('showToast', {
+ * text : 'Hello World',
+ * sticky : true,
+ * position : 'top-right',
+ * type : 'success',
+ * close : function () {console.log("toast is closed ...");}
+ * });
+ *
+ * To see some more examples please have a look into the Tests in src/test/javascript/ToastmessageTest.js
+ *
+ * For further style configuration please see corresponding css file: jquery-toastmessage.css
+ *
+ * This plugin is based on the jquery-notice (http://sandbox.timbenniks.com/projects/jquery-notice/)
+ * but is enhanced in several ways:
+ *
+ * configurable positioning
+ * convenience methods for different message types
+ * callback functionality when closing the toast
+ * included some nice free icons
+ * reimplemented to follow jquery plugin good practices rules
+ *
+ * Author: Daniel Bremer-Tonn
+**/
+(function($)
+{
+ var settings = {
+ inEffect: {opacity: 'show'}, // in effect
+ inEffectDuration: 600, // in effect duration in miliseconds
+ outEffectDuration: 200,
+ stayTime: 3000, // time in miliseconds before the item has to disappear
+ text: '', // content of the item. Might be a string or a jQuery object. Be aware that any jQuery object which is acting as a message will be deleted when the toast is fading away.
+ sticky: false, // should the toast item sticky or not?
+ type: 'notice', // notice, warning, error, success
+ position: 'top-right', // top-left, top-center, top-right, middle-left, middle-center, middle-right ... Position of the toast container holding different toast. Position can be set only once at the very first call, changing the position after the first call does nothing
+ closeText: '', // text which will be shown as close button, set to '' when you want to introduce an image via css
+ close: null // callback function when the toastmessage is closed
+ };
+
+ var methods = {
+ init : function(options)
+ {
+ if (options) {
+ $.extend( settings, options );
+ }
+ },
+
+ showToast : function(options)
+ {
+ var localSettings = {};
+ $.extend(localSettings, settings, options);
+
+ // declare variables
+ var toastWrapAll, toastItemOuter, toastItemInner, toastItemClose, toastItemImage;
+
+ toastWrapAll = (!$('.toast-container').length) ? $('<div></div>').addClass('toast-container').addClass('toast-position-' + localSettings.position).appendTo('body') : $('.toast-container');
+ toastItemOuter = $('<div></div>').addClass('toast-item-wrapper');
+ toastItemInner = $('<div></div>').hide().addClass('toast-item toast-type-' + localSettings.type).appendTo(toastWrapAll).html(localSettings.text).animate(localSettings.inEffect, localSettings.inEffectDuration).wrap(toastItemOuter);
+ toastItemClose = $('<div></div>').addClass('toast-item-close').prependTo(toastItemInner).html(localSettings.closeText).click(function() { $().toastmessage('removeToast',toastItemInner, localSettings) });
+ toastItemImage = $('<div></div>').addClass('toast-item-image').addClass('toast-item-image-' + localSettings.type).prependTo(toastItemInner);
+
+ if(navigator.userAgent.match(/MSIE 6/i))
+ {
+ toastWrapAll.css({top: document.documentElement.scrollTop});
+ }
+
+ if(!localSettings.sticky)
+ {
+ setTimeout(function()
+ {
+ $().toastmessage('removeToast', toastItemInner, localSettings);
+ },
+ localSettings.stayTime);
+ }
+ return toastItemInner;
+ },
+
+ showNoticeToast : function (message)
+ {
+ var options = {text : message, type : 'notice'};
+ return $().toastmessage('showToast', options);
+ },
+
+ showSuccessToast : function (message)
+ {
+ var options = {text : message, type : 'success'};
+ return $().toastmessage('showToast', options);
+ },
+
+ showErrorToast : function (message)
+ {
+
+ var options = {text : message, type : 'error'};
+ return $().toastmessage('showToast', options);
+
+ },
+
+ showWarningToast : function (message){
+
+ var options = {text : message, type : 'warning'};
+ return $().toastmessage('showToast', options);
+
+ },
+
+ cleanToast:function(){
+
+ $('.toast-container').empty();
+
+ },
+
+ removeToast: function(obj, options)
+ {
+ obj.animate({opacity: '0'}, settings.outEffectDuration, function()
+ {
+ obj.parent().animate({height: '0px'}, settings.outEffectDuration / 2, function()
+ {
+ obj.parent().remove();
+ });
+ });
+ // console.log( settings.outEffectDuration );
+ // callback
+ if (options && options.close !== null)
+ {
+ options.close();
+ }
+ }
+ };
+
+ $.fn.toastmessage = function( method ) {
+
+ // Method calling logic
+ if ( methods[method] ) {
+ return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ));
+ } else if ( typeof method === 'object' || ! method ) {
+ return methods.init.apply( this, arguments );
+ } else {
+ $.error( 'Method ' + method + ' does not exist on jQuery.toastmessage' );
+ }
+ };
+
+})(jQuery);
200 static/js/oo.js
View
@@ -0,0 +1,200 @@
+
+
+var oo = oo || {};
+oo.vars = oo.vars || {};
+oo.urls = oo.urls || {};
+
+/*
+
+
+ Logs
+ ====
+
+*/
+oo.log = function(){
+ try{
+ console.log.apply(console, arguments);
+ } catch(e){
+
+ }
+}
+
+
+/*
+
+
+ Restful API
+ ===========
+
+*/
+oo.api = {
+ settings:{
+ 'get':{dataType:"Json",type:"GET",fault:oo.fault } ,
+ 'post':{dataType:"Json",type:"POST",fault:oo.fault }
+ }
+};
+
+oo.api.init = function(){
+ oo.vars.csrftoken = oo.fn.get_cookie('csrftoken');
+ $.ajaxSetup({
+ crossDomain: false, // obviates need for sameOrigin test
+ beforeSend: function(xhr, settings) { if (!(/^(GET|HEAD|OPTIONS|TRACE)$/.test(settings.type))){ xhr.setRequestHeader("X-CSRFToken", oo.vars.csrftoken);}}
+ });oo.log("[oo.api.init]");
+}
+
+oo.api.process = function( result, callback, namespace ){
+ if( result.status == 'ok'){
+ if (typeof callback == "object"){
+ oo.toast( callback.message, callback.title );
+ } else return callback( result );
+ } else if( typeof result.error == "object" ){
+ oo.invalidate( result.error, namespace );
+ oo.toast( oo.i18n.translate("invalid form") , oo.i18n.translate("error"), {stayTime:3000, cleanup: true});
+ } else {
+ oo.toast( result.error , oo.i18n.translate("error"), {stayTime:3000, cleanup: true});
+ }
+}
+
+oo.api.urlfactory = function( url, factor, pattern ){
+ if( typeof factor == "undefined" ){ ds.log("[ds.m.api.urlfactory] warning'"); return url; };
+ pattern = typeof pattern == "undefined"? "/0/":pattern ;
+ return url.replace( pattern, ["/",factor,"/"].join("") )
+}
+
+/*
+
+
+ Modals (Bootstrap)
+ ==================
+
+*/
+oo.modals = {}
+oo.modals.init = function(){
+ $(".modal").each( function( i, el ){ var $el = $(el); $(el).css("margin-top",- Math.round( $(el).height() / 2 )); }); oo.log("[oo.modals.init]");
+};
+
+
+/*
+
+
+ Tooltip
+ =======
+
+*/
+oo.tooltip = {}
+oo.tooltip.init = function(){
+ $('body').tooltip({ selector:'[rel=tooltip]', animation: false, placement: function( tooltip, caller ){ var placement = $(caller).attr('data-tooltip-placement'); return typeof placement != "undefined"? placement: 'top'; } }); oo.log("[oo.tooltip.init]");};
+
+
+/*
+
+
+ Toast
+ =====
+
+*/
+oo.toast = function( message, title, options ){
+ if(!options){options={}}if(typeof title=="object"){options=title;title=undefined}if(options.cleanup!=undefined)$().toastmessage("cleanToast");var settings=$.extend({text:"<div>"+(!title?"<h1>"+message+"</h1>":"<h1>"+title+"</h1><p>"+message+"</p>")+"</div>",type:"notice",position:"middle-center",inEffectDuration:200,outEffectDuration:200,stayTime:3e3},options);$().toastmessage("showToast",settings)
+};
+
+
+/*
+
+
+ Invalidate, Fault
+ =================
+
+*/
+oo.invalidate = function( errors, namespace ){ if (!namespace){ namespace = "id";} oo.log("[oo.invalidate] namespace:",namespace, " errors:",errors );
+ for (var i in errors){
+ if( i.indexOf("_date") != -1 ){
+ $("#"+namespace+"_"+i+"_day").parent().addClass("invalid");
+ continue;
+ } else if (i.indexOf("_type") != -1 ){
+ $("#"+namespace+"_"+i).parent().addClass("invalid");
+ continue;
+ } else if( i.indexOf("_hours") != -1 || i.indexOf("_minutes") != -1 ) {
+ $("#"+namespace+"_"+i).parent().addClass("invalid");
+ continue;
+ } else if(i.indexOf("captcha") != -1 ) {
+ $("#recaptcha_response_field").addClass("invalid");
+ continue;
+ }
+ $("#"+namespace+"_"+i).addClass("invalid");
+ }
+}
+
+oo.fault = function( message ){
+ oo.log("[ds.m.handlers.fault] message:", message );
+ message = typeof message == "undefined"? "": message;
+ oo.toast( message, oo.i18n.translate("connection error"), {stayTime:3000, cleanup: true});
+}
+
+
+/*
+
+
+ Common function
+ ===============
+
+*/
+oo.fn = {};
+oo.fn.slug = function( sluggable ){
+ return sluggable.replace(/[^a-zA-Z 0-9-]+/g,'').toLowerCase().replace(/\s/g,'-');
+};
+
+oo.fn.get_cookie = function (e){
+ var t=null;if(document.cookie&&document.cookie!=""){var n=document.cookie.split(";");for(var r=0;r<n.length;r++){var i=jQuery.trim(n[r]);if(i.substring(0,e.length+1)==e+"="){t=decodeURIComponent(i.substring(e.length+1));break}}}return t
+};
+
+
+/*
+
+
+ I18n
+ ====
+
+*/
+oo.i18n = { lang:'fr-FR'};
+oo.i18n.translate = function( key ){
+ var l = oo.i18n.lang;
+ if ( oo.i18n.dict[l][key] == undefined )
+ return key;
+ return oo.i18n.dict[l][key];
+}
+
+oo.i18n.dict = {
+ 'fr-FR':{
+ "connection error":"Connection error",
+ "warning":"Attention",
+ "delete selected absence":"Voulez-vous supprimer cette absence?",
+ "offline device":"Échec de la connexion.",
+ "check internet connection":"Veuillez vérifier la connexion internet de la tablette.",
+ "welcome back":"welcome back",
+ "loading":"chargement en cours…",
+ "form errors":"Erreurs dans le formulaire",
+ "error":"Erreur",
+ "invalid form":"Veuillez vérifier les champs en rouge.",
+ "empty dates":"Les dates de dé en rouge.",
+ "empty message field":"Le message est vide.",
+ "message sent":"Message envoyé",
+ "timeout device":"Connexion trop lente.",
+ "try again later": "Veuillez réessayer dans quelques instants.",
+ "saving":"enregistrement en cours…",
+ "changes saved":"Modifications Sauvegardées",
+ "changes saved successfully":"Modifications Sauvegardées",
+ "password should be at least 8 chars in length":"Le mot de passe doit faire au moins 8 caractères.",
+ "password too short":"Le mot de passe est trop court",
+ "password changed":"Le mot de passe a été changé",
+ "new passwords not match":"Saisissez à nouveau le nouveau mot de passe.",
+ "invalid password":"Veuillez vérifier votre ancien mot de passe en respectant les minuscules et les majuscules.",
+ "sms message sent":"SMS envoyé(s) avec succès.",
+ "sms message sent failed":"Le SMS n'a pas pu être envoyé.",
+ "sms invalid message":"Le texte du SMS est invalide.",
+ "sms invalid phone numbers":"Numéro(s) de téléphone invalide(s)",
+ "list numbers sms failure":"Certains SMS n'ont pu être envoyés.",
+ "to change password": "Veuillez changer votre <br/> <b>mot de passe</b>",
+ "please check accepted terms": "Veuillez accepter les conditions d'utilisation",
+
+ }
+};
295 static/js/oo/glue.js
View
@@ -0,0 +1,295 @@
+var oo = oo || {}; oo.vars.pin = oo.vars.pin || {}; oo.glue = {};
+
+/*
+
+
+ Magic
+ =====
+
+*/
+oo.magic = oo.magic || {};
+oo.magic.reload = function(){
+ window.location.reload();
+}
+
+oo.magic.page = oo.magic.page || {};
+
+oo.magic.page.add = function( result ){
+ oo.log("[oo.magic.page.add]", result);
+ window.location.reload();
+}
+
+oo.magic.pin = oo.magic.pin || {};
+oo.magic.pin.add = function( result ){
+ oo.log("[oo.magic.pin.add]", result);
+ window.location.reload();
+}
+oo.magic.pin.get = function( result ){
+ oo.log("[oo.magic.pin.get]", result);
+ // window.location.reload();
+}
+
+
+
+/*
+
+
+ Pin/Page Ajax API
+ =================
+
+*/
+oo.api.pin = {};
+oo.api.pin.add = function( params ){ oo.log( '[oo.api.pin.add]', params );
+ $.ajax( $.extend( oo.api.settings.post,{
+ url: oo.urls.add_pin,
+ data: params,
+ success:function(result){
+ oo.log( "[oo.api.pin.add] result:", result );
+ oo.api.process( result, oo.magic.pin.add, "id_add_pin" );
+ }
+ }));
+};
+
+oo.api.pin.get = function( pk, params, callback ){
+ $.ajax( $.extend( oo.api.settings.get,{
+ url: oo.api.urlfactory( oo.urls.get_pin, pk ),
+ data: params,
+ success:function(result){
+ oo.log( "[oo.api.pin.get] result:", result );
+ oo.api.process( result, typeof callback == "function"? callback: oo.magic.pin.get );
+ }
+ }));
+};
+
+oo.api.pin.edit = function( pk, params, callback ){
+ $.ajax( $.extend( oo.api.settings.post,{
+ url: oo.api.urlfactory( oo.urls.edit_pin, pk ),
+ data: params,
+ success:function(result){
+ oo.log( "[oo.api.pin.edit] result:", result );
+ oo.api.process( result, typeof callback == "function"? callback: oo.magic.reload,"id_edit_pin" );
+ }
+ }));
+};
+
+oo.api.pin.delete = function( pk, params, callback ){
+ $.ajax( $.extend( oo.api.settings.post,{
+ url: oo.api.urlfactory( oo.urls.edit_pin, pk ),
+ data: $.extend({'method':'DELETE'}, params),
+ success:function(result){
+ oo.log( "[oo.api.pin.delete] deleted : "+ pk);
+ oo.api.process( result, typeof callback == "function"? callback: oo.magic.reload);
+ }
+ }));
+};
+
+oo.api.pin.publish = function( pk, params, callback ){
+ $.ajax( $.extend( oo.api.settings.post,{
+ url: oo.api.urlfactory( oo.urls.publish_pin, pk ),
+ data: params,
+ success:function(result){
+ //oo.log( "[oo.api.pin.publish] pin #"+ pk+"new status is : "+params.new_status);
+ oo.api.process( result, typeof callback == "function"? callback: oo.magic.reload);
+ }
+ }));
+};
+
+
+oo.api.page = {};
+oo.api.page.add = function( params ){
+ oo.log("[oo.api.page.add]");
+ $.ajax( $.extend( oo.api.settings.post,{
+ url: oo.urls.add_page,
+ data: params,
+ success:function(result){
+ oo.log( "[oo.api.page.add] result:", result );
+ oo.api.process( result, oo.magic.page.add, "id_add_page" );
+ }
+ }));
+}
+
+/*
+
+
+ Pin/Page Init
+ =============
+
+ Require wysihtml5 plugin
+
+*/
+oo.glue = {};
+oo.glue.init = function(){ oo.log("[oo.glue.init]");
+ $("#add-page").on("click", function(event){ event.preventDefault(); oo.api.page.add({
+ title_en:$("#id_add_page_title_en").val(),
+ title_fr:$("#id_add_page_title_fr").val(),
+ slug:$("#id_add_page_slug").val()
+ });});
+
+ $("#add-pin").on("click", function(event){ event.preventDefault();
+ var el = $(this);
+ var permalink = $("#id_add_pin_permalink").val();
+ var page_slug = el.attr("data-page-slug");
+ var pin_slug = el.attr("data-pin-slug");
+
+ oo.log("[oo.glue.init:click] #add-pin, page-slug:", page_slug, ", parent-pin-slug:", pin_slug );
+
+ var params = {
+ title_en:$("#id_add_pin_title_en").val(),
+ title_fr:$("#id_add_pin_title_en").val(),
+ title_it:$("#id_add_pin_title_en").val(),
+ slug:$("#id_add_pin_slug").val()
+ }
+
+
+ if ( typeof permalink != "undefined" && permalink.length ){
+ $.extend(params,{permalink:permalink});
+ }
+
+ if ( typeof page_slug != "undefined" && page_slug.length ){
+ $.extend(params,{page_slug:page_slug});
+ }
+
+ if ( typeof pin_slug != "undefined" && pin_slug.length ){
+ $.extend(params,{parent_pin_slug:pin_slug});
+ }
+ oo.api.pin.add( params );
+ });
+
+
+ $("#edit-pin").on("click", function(event){ event.preventDefault(); oo.api.pin.edit( $(this).attr("data-pin-id"),{
+ title:$("#id_edit_pin_title").val(),
+ content:$("#id_edit_pin_content").val(),
+ abstract:$("#id_edit_pin_abstract").val()
+ });});
+
+ $("#id_add_page_title_en").on('keyup', function( event ){ $("#id_add_page_slug").val( oo.fn.slug( $("#id_add_page_title_en").val() ) ) });
+ $("#id_add_pin_title_en").on('keyup', function( event ){ $("#id_add_pin_slug").val( oo.fn.slug( $("#id_add_pin_title_en").val() ) ) });
+
+
+
+ // html5 pin editor
+ try{
+ var editor = new wysihtml5.Editor("id_edit_pin_content", { // id of textarea element
+ toolbar: "wysihtml5-toolbar", // id of toolbar element
+ parserRules: wysihtml5ParserRules // defined in parser rules set
+ });
+ } catch(e){
+ oo.log("[oo.glue.init:exception]",e);
+ }
+ // $("#edit-section-modal").modal('show')
+ $(document).click( function(event){ $(".invalid").removeClass('invalid');});
+
+ // ADD PIN
+ $(document).on("click",".add-pin", function(event){
+ var el = $(this);
+ oo.log("[oo.glue.init:click] .add-pin", el.attr("data-page-slug"), el.attr('data-parent-pin-slug') );
+ // $('#add-pin-modal').modal('show');
+ $('#add-pin-modal').reveal();
+
+ if( typeof el.attr('data-parent-pin-slug') == "undefined"){
+ $('#parent-pin-slug').empty();
+ } else {
+ $('#parent-pin-slug').html( "&rarr;" + el.attr('data-parent-pin-slug') )
+ }
+
+ if( typeof el.attr('data-page-slug') == "undefined"){
+ $('#parent-page-slug').empty(); // news!
+ } else {
+ $('#parent-page-slug').html( "&rarr;" + el.attr('data-parent-slug') )
+ }
+
+ $('#add-pin').attr("data-parent-pin-slug", el.attr('data-parent-pin-slug') );
+ $('#add-pin').attr("data-page-slug", el.attr('data-page-slug') );
+
+ });
+
+ $(document).on("click",".edit-pin", function(event){
+ // load content before all
+ oo.api.pin.get( $(this).attr('data-pin-id'), {}, function(result){
+ // $('#edit-pin-modal').modal('show');
+ $('#id_edit_pin_title').val( result.object.title )
+ $('#id_edit_pin_abstract').val( result.object.abstract )
+ $('#id_edit_pin_content').val( result.object.content )
+ editor.setValue( result.object.content );
+ // $('#edit-pin-modal').result.object.title
+ $('#edit-pin').attr("data-pin-id",result.object.id );
+ });
+ oo.log("eeee");
+ });
+
+ // Delete PIN
+ $(document).on("click",".delete-pin", function(event){
+ oo.api.pin.delete($(this).attr('data-pin-id'),{});
+ });
+
+ //Publish PIN
+ $(document).on("click",".publish-pin", function(event){
+ oo.api.pin.publish($(this).attr('data-pin-id'),{'new_status':$(this).attr('new-status')});
+ });
+
+};
+
+
+oo.glue.upload = { is_dragging:false }
+oo.glue.upload.enable = function()
+{
+ oo.log("[oo.glue.upload.enable]");
+ $('#fileupload').fileupload('enable');
+}
+
+oo.glue.upload.disable = function(){
+ oo.log("[oo.glue.upload.disable]");
+ $('#fileupload').fileupload('disable');
+}
+oo.glue.upload.init = function(){
+ oo.log("[oo.glue.init]");
+
+ $('#fileupload').fileupload({
+ url: oo.urls.pin_upload,
+ dataType: 'json',
+ sequentialUploads: true,
+ dragover: function(e,data){
+ if (oo.glue.upload.is_dragging)
+ return;
+ oo.log("[oo.glue.upload] dragover");
+ oo.glue.upload.is_dragging = true;
+ },
+ drop:function(e,data){
+ oo.log("[oo.glue.upload] drop");
+ oo.glue.upload.is_dragging = false;
+ },
+ done: function (e, data) {
+ oo.log( e, data.result);
+ oo.toast("uploaded finished", { stayTime: 2000,cleanup:true });
+ if( data.result.status == "ok"){
+ oo.toast( "COMPLETED GUY!:!!!" );
+ } else{
+ oo.toast( data.result.error, ds.i18n.translate("error"), { stayTime: 2000, cleanup:true });
+ }
+ },
+ start: function (e, data) {
+ oo.toast(oo.i18n.translate("start uploading"), { stayTime: 2000 });
+ },
+ fail: function( e, data){
+ oo.log(e, data);
+ oo.fault( e.type);
+ },
+ progressall: function (e, data) {
+ var progress = parseInt(data.loaded / data.total * 100, 10);
+ $('#progress .bar').width( progress + '%');
+ },
+
+ add: function (e, data) {
+ var slug = $('body').attr('data-page-slug');
+ if( slug.length > 0 ){
+ data.formData = { 'page_slug':slug };
+ }
+ data.submit();
+
+ }
+ });
+ // enabled by default, or comment
+ // oo.glue.upload.disable();
+};
+
+
10 static/js/walt.js
View
@@ -1 +1,11 @@
+var walt = {};
+
+walt.reveal = {}
+
+walt.reveal.init = function(){
+ $('.add-pin-modal').click(function(e) {
+ e.preventDefault();
+ $('#add-pin').reveal();
+ });
+};
176 static/less/style.less
View
@@ -72,4 +72,180 @@ h2{
padding-bottom: @grid-padding;
border-bottom: 1px solid #ccc;
+}
+
+
+/*
+
+ Reveal Modals
+ -------------
+*/
+
+.reveal-modal-bg {
+ position: fixed;
+ height: 100%;
+ width: 100%;
+ background: #000;
+ background: rgba(0,0,0,.8);
+ z-index: 100;
+ display: none;
+ top: 0;
+ left: 0;
+}
+
+.reveal-modal {
+ visibility: hidden;
+ top: 0;
+ left: 50%;
+ margin-left: -245px;
+ width: 470px;
+ background: #fff;
+ position: fixed;
+ z-index: 101;
+ padding: 30px 40px 34px;
+
+ -moz-box-shadow: 0 0 10px rgba(0,0,0,.4);
+ -webkit-box-shadow: 0 0 10px rgba(0,0,0,.4);
+ -box-shadow: 0 0 10px rgba(0,0,0,.4);
+}
+
+.reveal-modal.small { width: 200px; margin-left: -140px;}
+.reveal-modal.medium { width: 400px; margin-left: -240px;}
+.reveal-modal.large { width: 600px; margin-left: -340px;}
+.reveal-modal.xlarge { width: 800px; margin-left: -440px;}
+
+.reveal-modal .close-reveal-modal {
+ font-size: 28px;
+ line-height: .5;
+ position: absolute;
+ top: 8px;
+ right: 11px;
+ color: #aaa;
+ text-shadow: 0 -1px 1px rbga(0,0,0,.6);
+
+ cursor: pointer;
+}
+
+input[type="text"]{
+ -webkit-border-radius: 0px;
+ -moz-border-radius: 0px;
+ border-radius: 0px
+}
+
+input, button, select, textarea {
+ .mono(16px)
+}
+
+
+
+
+/*
+
+ Toast
+
+*/
+@toast-width: 280px;
+@base-color: #292929;
+.toast-container {
+ width: @toast-width;
+ z-index: 1999999999;
+ position: fixed;
+ left: 50%;
+ top: 50%;
+
+ &.toast-position-middle-center {
+ margin-left: -@toast-width/2;
+ margin-top: -40px;
+ }
+ &.toast-position-top-left {
+ left: 20px;
+ top: 20px;
+ }
+}
+
+
+* html .toast-container {
+ position: absolute;
+}
+@original-color: darken(@base-color, 38%);
+
+.toast-item {
+ height: auto;
+ // opacity: 0.95;
+ padding: 0 0 0 0;
+ font-size: 14px;
+ line-height: 20px;
+ display: block;
+ position: relative;
+ margin: 0 0 12px 0;
+
+ background: white;
+ border: 1px solid fade( @original-color, 15%);
+
+ .mono(16px, normal, 1.414);
+
+ h1{
+ color: #191919;
+ border-bottom: 1px solid lighten( @original-color, 15%);
+ margin: 12px;
+ //.serif-slant(18px, normal, 1.44);
+ .mono(16px, normal, 1.414);
+
+ padding: 0 46px 12px 0;
+ }
+
+ p{
+ text-align: left;
+ margin: 0 12px 14px 12px;
+
+ }
+
+}
+
+
+p.invalid{
+ background-color: fade( #cc1400, 20%);
+ border: 1px solid #cc1400;
+ margin: @grid-padding/3;
+ padding: @grid-padding/3;
+ .border-radius(2px);
+}
+
+input.invalid{
+ border: 1px solid #cc1400;
+}
+
+.toast-item-close {
+ background:url("../../img/icons/32-Cross-white.png");
+ width:32px;
+ height:32px;
+ position: absolute;
+ top:7px;
+ right:7px;
+}
+
+.toast-item-image {
+ width:32px;
+ height: 32px;
+ margin-left: 10px;
+ margin-top: 10px;
+ margin-right: 10px;
+ float:left;
+}
+
+.toast-item-image-notice {
+ /*background:url("../../img/icons/32-Alert.png");*/
+ display:none;
+}
+
+.toast-item-image-success {
+ background:url(../../images/success.png);
+}
+
+.toast-item-image-warning {
+ background:url(../../images/warning.png);
+}
+
+.toast-item-image-error {
+ background:url(../../images/error.png);
}
<