Commits

Gabriele Lanaro committed b9b346e Merge

merged with default

Comments (0)

Files changed (13)

 glob:*.pyc
+glob:.ropeproject
+glob:tests/setup_auth.el
+glob:\#*
+glob:.\#*

.ropeproject/config.py

-# The default ``config.py``
-
-
-def set_prefs(prefs):
-    """This function is called before opening the project"""
-
-    # Specify which files and folders to ignore in the project.
-    # Changes to ignored resources are not added to the history and
-    # VCSs.  Also they are not returned in `Project.get_files()`.
-    # Note that ``?`` and ``*`` match all characters but slashes.
-    # '*.pyc': matches 'test.pyc' and 'pkg/test.pyc'
-    # 'mod*.pyc': matches 'test/mod1.pyc' but not 'mod/1.pyc'
-    # '.svn': matches 'pkg/.svn' and all of its children
-    # 'build/*.o': matches 'build/lib.o' but not 'build/sub/lib.o'
-    # 'build//*.o': matches 'build/lib.o' and 'build/sub/lib.o'
-    prefs['ignored_resources'] = ['*.pyc', '*~', '.ropeproject',
-                                  '.hg', '.svn', '_svn', '.git']
-
-    # Specifies which files should be considered python files.  It is
-    # useful when you have scripts inside your project.  Only files
-    # ending with ``.py`` are considered to be python files by
-    # default.
-    #prefs['python_files'] = ['*.py']
-
-    # Custom source folders:  By default rope searches the project
-    # for finding source folders (folders that should be searched
-    # for finding modules).  You can add paths to that list.  Note
-    # that rope guesses project source folders correctly most of the
-    # time; use this if you have any problems.
-    # The folders should be relative to project root and use '/' for
-    # separating folders regardless of the platform rope is running on.
-    # 'src/my_source_folder' for instance.
-    #prefs.add('source_folders', 'src')
-
-    # You can extend python path for looking up modules
-    #prefs.add('python_path', '~/python/')
-
-    # Should rope save object information or not.
-    prefs['save_objectdb'] = True
-    prefs['compress_objectdb'] = False
-
-    # If `True`, rope analyzes each module when it is being saved.
-    prefs['automatic_soa'] = True
-    # The depth of calls to follow in static object analysis
-    prefs['soa_followed_calls'] = 0
-
-    # If `False` when running modules or unit tests "dynamic object
-    # analysis" is turned off.  This makes them much faster.
-    prefs['perform_doa'] = True
-
-    # Rope can check the validity of its object DB when running.
-    prefs['validate_objectdb'] = True
-
-    # How many undos to hold?
-    prefs['max_history_items'] = 32
-
-    # Shows whether to save history across sessions.
-    prefs['save_history'] = True
-    prefs['compress_history'] = False
-
-    # Set the number spaces used for indenting.  According to
-    # :PEP:`8`, it is best to use 4 spaces.  Since most of rope's
-    # unit-tests use 4 spaces it is more reliable, too.
-    prefs['indent_size'] = 4
-
-    # Builtin and c-extension modules that are allowed to be imported
-    # and inspected by rope.
-    prefs['extension_modules'] = []
-
-    # Add all standard c-extensions to extension_modules list.
-    prefs['import_dynload_stdmods'] = True
-
-    # If `True` modules with syntax errors are considered to be empty.
-    # The default value is `False`; When `False` syntax errors raise
-    # `rope.base.exceptions.ModuleSyntaxError` exception.
-    prefs['ignore_syntax_errors'] = False
-
-    # If `True`, rope ignores unresolvable imports.  Otherwise, they
-    # appear in the importing namespace.
-    prefs['ignore_bad_imports'] = False
-
-
-def project_opened(project):
-    """This function is called after opening the project"""
-    # Do whatever you like here!

.ropeproject/globalnames

-�}q(Ubloggerq]q(U
-(U

.ropeproject/history

-�]q(]q]qe.

.ropeproject/objectdb

-�}q(Ublogger_bridge.pyq}qULispInteractive.__init__qcrope.base.oi.memorydb
-ScopeInfo
-q)�q}qUinstanceqUdefinedq	hULispInteractiveq
-���q
-namedtupleqh)�q}qUbuiltinUstr�qhh�q
-;; Cleaning
-;;
+;; Variables
 
 (defvar blogger-mode-map nil "Local keymap for dired-mode buffers.")
 (defvar blogger-username nil "Username used to log in")
 (defvar blogger-password nil "Password to log in")
+(defvar blogger-default-blog-name nil "Default blog to edit")
+
+(defvar blogger-initialized nil "Check if the initialization procedure was successful")
+
+
+;; Faces
+(defface blogger-date
+  '((t (:inherit file-name-shadow))) "Face for date displaying")
+(defface blogger-title
+  '((t (:inherit font-lock-function-name-face))) "Face for displaying blog titles")
+(defface blogger-tags
+  '((t (:inherit font-lock-variable-name-face))) "Face for displaying tags")
+
 
 (defun blogger-post ()
   "Generic function to upload a post in blogger, it determines
 the current major mode and do exporting in various forms"
   (interactive)
-  (blogger-authenticate)
+  
+  (when (not blogger-initialized)
+    (blogger-initialize))
+
   (let (title id)
     (setq title (read-from-minibuffer "Title: "))
     (setq blogger-buffer-title title)
     ;; The blogger-bridge-post return id of the post yet posted.
     (setq blogger-buffer-post-id (blogger-bridge-post title (blogger-filter-content)))
+    (message (format "Post '%s' successfully posted" title))
     )
   )
 
+(defun blogger-initialize ()
+  "Initialize the blogger object with authentication and fetching of blogs/entires"
+  (blogger-authenticate)
+  (blogger-bridge-refresh)
+  (if blogger-default-blog-name
+      (blogger-set-blog blogger-default-blog-name)
+    (blogger-select-blog)
+    )
+  (setq blogger-initialized t)
+  )
+
+(defun blogger-prompt-entry ()
+  "Prompt an entry by name in the current blog, how to handle duplicate titles? mabye with numbers appended by recentness"
+  )
+
 (defun blogger-update-post ()
   "Update a blog post"
   (interactive)
     (setq title blogger-buffer-title)
     (setq content (blogger-filter-content))
     (blogger-bridge-update-post id title content)
+    (message "Post successfully updated")
     )
   )
 
   "Starts a buffer with the blogs listed and shows the entries of
   each blog, in Blogger mode"
   (interactive)
-  (blogger-authenticate)
+
+  (when (not blogger-initialized)
+    (blogger-initialize))
+
   (pop-to-buffer (generate-new-buffer "Blogger"))
+  
   (let ((buffer-read-only nil))
     (blogger-create-bloglist))
-  (blogger-mode))
+  
+  (blogger-mode)
+  )
 
 (defun blogger-delete ()
   "Delete post under cursor"
   (interactive)
-  (let (blog-id post-id)
-    (setq blog-id (get-text-property (point) 'blog-id))
+  (let (post-id)
     (setq post-id (get-text-property (point) 'entry-id))
-    (when (and blog-id post-id)
-      (blogger-bridge-delete-post post-id blog-id)
-      (blogger-update-view)))
+    
+    (when (and post-id (y-or-n-p "Delete Post?"))
+      (blogger-bridge-delete-post post-id)
+      (blogger-bridge-refresh)
+      (blogger-update-view)
+      (message "Entry successfully deleted"))
+    )
   )
 
 (defun blogger-rename-post ()
     (blogger-bridge-update-title (get-text-property 'blog-id) (get-text-property 'post-id)))
   (blogger-update-view))
 
+(defun blogger-update-view ()
+  "Refill the buffer with info about the blog"
+  (interactive)
+  (save-excursion
+    (let ((buffer-read-only nil))
+      (erase-buffer)
+      (blogger-create-bloglist)
+      )
+    )
+  )
+
 (defun blogger-quit ()
   "quit the blogger buffer"
   (interactive)
   (when (eq major-mode 'blogger-mode)
     (kill-buffer (current-buffer))))
 
-(defun blogger-update-view ()
-  "Refill the buffer with info about the blog"
-  (interactive)
-  (let ((buffer-read-only nil))
-    (erase-buffer)
-    (blogger-create-bloglist)))
-
 
 ;; Utility/Displaying functions
 (defun blogger-authenticate ()
   "authenticate to blogger system"
-  (blogger-check-usn-pass)
-  (blogger-bridge-authenticate)
+  (when (not (or blogger-username blogger-password))
+    (blogger-prompt-usn-pass))
+  
+  (when (not (blogger-bridge-authenticate))
+    ;; Reset the value of the blogger username and password
+    (setq blogger-username nil)
+    (setq blogger-password nil)
+    (error "Invalid username/password"))
   )
 
-(defun blogger-check-usn-pass ()
-  "Check if username and password are defined and define it prompting the user"
-  (when (not (or blogger-username blogger-password))
-    (setq blogger-username (read-from-minibuffer "Username: "))
-    (setq blogger-password (read-passwd "Password: "))))
+(defun blogger-prompt-usn-pass ()
+  "Define the blogger-username variable and blogger-password variable"
+  (interactive)
+  (setq blogger-username (read-from-minibuffer "Username: "))
+  (setq blogger-password (read-passwd "Password: "))
+  )
 
+(defun blogger-select-blog ()
+  "Ask the user for the blog and set the current blog"
+  (interactive)
+  (blogger-set-blog (blogger-prompt-blog))
+  )
+
+(defun blogger-prompt-blog ()
+  "Prompt the user for a blog with completion support"
+  (setq blogger-default-blog-name 
+	(completing-read "Select a Blog (TAB for completion): " (blogger-bridge-get-blog-names))
+  )
+)
+
+(defun blogger-set-blog (blog-name)
+  "Set the blog specified by BLOG-NAME as the current edited blog"
+  (interactive)
+  (blogger-bridge-set-current-blog-by-name blog-name))
 
 (defun blogger-create-bloglist ()
-  "Create the list of blogs with respective entries"
-  ;; Inserting stuff for each blog
-  (dolist (blog (blogger-bridge-get-blogs)) 
-    (let ((btitle (nth 1 blog)) ;; Fetch blog name and id
-	  (bid (nth 0 blog)))
-      ;; Inserting the text with the property blog-id to fetch later the blog and entries
-      (insert (propertize (concat "+ " btitle) 'blog-id bid 'face 'dired-header)) 
-      (insert "\n")
-      ;; Now do the same thing with each entries assigning properties
-      (dolist (entry (blogger-bridge-get-entries bid)) 
-	(let ((etitle (nth 1 entry))
-	      (eid (nth 0 entry))
-	      (edate (nth 2 entry)))
-	  (insert (propertize (concat "    - " edate "  ") 'blog-id bid 'entry-id eid))
-	  (insert (propertize (concat etitle "\n") 'blog-id bid 'entry-id eid 'face 'dired-directory))
-	  )
-	) ;; End dolist entries
+  "Create the list of entries in the selected blog"
+  (dolist (entry (blogger-bridge-get-entries)) 
+    ;; Unpack the entry in various parts
+    (let ((etitle (nth 1 entry))
+	  (eid (nth 0 entry))
+	  (edate (nth 2 entry))
+	  (entry-tags (nth 3 entry)))
+      
+      ;; Insert date
+      (insert (propertize (concat "-" edate "  ") 'face 'blogger-date))
+      (insert (propertize (concat etitle "  ") 'face 'blogger-title))
+      ;; If there are tags
+      
+      (cond 
+       ;; If entry-tags is nil do nothing
+       ((eq entry-tags nil) (insert ""))
+       ;; If it is a string insert the string alone
+       ((stringp entry-tags) (insert entry-tags))
+       ;; If it is a list insert the tags separated by :
+       ((sequencep entry-tags)
+	(insert 
+	 (propertize
+	  (mapconcat 'identity entry-tags ":") 'face 'blogger-tags)))
+       )
+      
+      ;; Apply entry-id property to text
+      (put-text-property (line-beginning-position)
+			 (line-end-position) 'entry-id eid)
+      (insert (propertize "\n" 'entry-id eid))
       )
     ) ;; End dolist blogs
   )
 
 ;; Misc
 (defun blogger-upload-image (filename)
-  "thisandthat."
+  "Upload an image to the album Blogger in picasa web albums using the same blogger account"
   (interactive "fSelect an Image: ")
-  (blogger-authenticate)
+  (blogger-prompt-usn-pass)
+  
   (let (url)
     (setq url (blogger-bridge-upload-image filename))
     (kill-new url)
     (message "C-y to paste the uploaded image URL")
     )
-
   )
 
 ;; Making a keymap!!!

blogger_bridge.py

         self.authenticated = False
 
     def authenticate(self):
+        '''Authenticate the user and return True if succeed else False
+        '''
+        
         username = lisp["blogger-username"].value()
         password = lisp["blogger-password"].value()
         
             self.blogger = Blogger(username, password)
             self.authenticated = True
         except:
-            lisp.message("Invalid username, password")
-        self.update()
+            return False
+        return True
+    
+    def refresh(self):
+        '''refresh the cached list of blogs and entries
+        '''
         
-    def update(self):
         self.blogs = list(self.blogger.get_blogs())
 
+    @property
+    def blog(self):
+        if hasattr(self,"_blog"):
+            return self._blog
+        else:
+            lisp.error("Current Blog not selected")
+    
+    def set_blog(self, blog_id):
+        self._blog = self.get_blog(blog_id)
+
+    blog.setter(set_blog)
+
+    
     def get_blogs(self):
         return [[blog.id, blog.name] for blog in self.blogs]    
     
-    def get_entries(self, blog_id):
-        blog = self.get_blog(blog_id)
+    def get_blog_id(self,name):
+        '''get a blog by name
+        '''
+        try:
+            return next(blog.id for blog in self.blogs if blog.name == name)
+        except StopIteration:
+            lisp.error("Blog name '%s' not correct"%name)
+    
+    def get_entries(self):
+        '''get entries of the current blog selected (attr .blog)
+        '''
+        
+        blog = self.blog
         
         entries = blog.get_entries()
-        return [[entry.id ,entry.title, entry.updated.strftime("%d/%m/%Y")] \
+        return [[entry.id ,entry.title, entry.updated.strftime("%d/%m/%Y"), entry.category] \
                     for entry in entries]
     
+    def get_blog_names(self):
+        '''return a list of the blog names
+        '''
+        
+        return [bl.name for bl in self.blogs]
+
     def get_blog(self, blog_id):
         return next(blog for blog in self.blogs if blog.id == blog_id)
     
     def get_a_blog(self,blog_id=None):
-         blog = self.blogs[0] if blog_id == None else self.get_blog(blog_id)
-         return blog
+        blog = self.blogs[0] if blog_id == None else self.get_blog(blog_id)
+        return blog
 
-    def post(self, title, content, blog_id = None):
-        blog = self.get_a_blog(blog_id)
-        entry = blog.publish_post(title, content)
+    def post(self, title, content):
+        '''Post this article to the current blog,
+        return the article id
+        '''
+        entry = self.blog.publish_post(title, content)
         return entry.id
     
     def update_post(self, post_id, title=None, content=None):
         
         return c.add_photo(os.path.expanduser(filename))
 
+    def get_post_tags(self):
+        return 
 li = LispInteractive()
 
 # Exposing functions
 authenticate = li.authenticate
-get_blogs = li.get_blogs
+refresh = li.refresh
+
 get_entries = li.get_entries
+get_blog_names = li.get_blog_names
+get_blog_id = li.get_blog_id
+set_current_blog_by_name = lambda name: li.set_blog(li.get_blog_id(name))
+
 post = li.post
 rst2blogger = filters.pipe(filters.rst2html,
                            filters.extract_body,
                            filters.remove_space_between_tags)
 delete_post = li.delete_post
 update_post = li.update_post
+get_post_tags = li.get_post_tags
 upload_image = li.upload_image
 
 # Interactive functions

tests/setup_load.el

+(require 'pymacs)
+(add-to-list 'pymacs-load-path "~/workspace/blogger/pythonblog/")
+(pymacs-load "blogger_bridge" "blogger-bridge-")
+(load-file "~/workspace/blogger/pythonblog/blogger-mode.el")

tests/test_blog_error.el

+(load-file "setup_load.el")
+(load-file "setup_auth.el")
+(setq blogger-default-blog-name "asdf")
+(blogger-show)

tests/test_open.el

+(load-file "setup_load.el")
+(load-file "setup_auth.el")
+(setq blogger-default-blog-name "Riding Python")
+(blogger-show)

tests/test_open_error.el

+(load-file "setup_load.el")
+(load-file "setup_auth.el")
+(setq blogger-username "gabriele.lanaro")
+(setq blogger-password "sdfh")
+(blogger-show)

tests/test_post.el

+(load-file "setup_load.el")
+(load-file "setup_auth.el")
+(find-file "../articles/testarticle.rst")
+(blogger-post)

tests/test_update_post.el

+(load-file "setup_load.el")
+(load-file "setup_auth.el")
+(find-file "../articles/testarticle.rst")
+(blogger-post)
+(blogger-update-post)