# -*- coding: utf-8 -*- """ @author: Fabio Erculiani @contact: lxnay@sabayon.org @copyright: Fabio Erculiani @license: GPL-2 B{Entropy Package Manager Client}. """ import os from entropy.const import etpConst, const_isstring, const_convert_to_unicode from entropy.output import bold, darkgreen, red, darkred, blue, purple, brown, \ teal, print_info, print_warning, print_error from entropy.services.client import WebService from entropy.client.services.interfaces import Document, DocumentFactory, \ ClientWebService from entropy.i18n import _ from entropy.cli import get_entropy_webservice as _get_service import entropy.tools def ugc(options): if not options: return -10 cmd = options.pop(0) do_force = False myopts = [] for opt in options: if opt == "--force": do_force = True elif opt.startswith("--"): print_error(red(" %s." % (_("Wrong parameters"),) )) return -10 else: myopts.append(opt) options = myopts rc = -10 from entropy.client.interfaces import Client entropy_client = None try: entropy_client = Client() if cmd == "login": if options: rc = _ugc_login(entropy_client, options[0], force = do_force) elif cmd == "logout": if options: rc = _ugc_logout(entropy_client, options[0]) elif cmd == "documents": if options: rc = _ugc_documents(entropy_client, options) elif cmd == "vote": if options: rc = _ugc_votes(entropy_client, options) finally: if entropy_client is not None: entropy_client.shutdown() return rc def _ugc_login(entropy_client, repository, force = False): if repository not in entropy_client.repositories(): print_error(red("%s: %s." % (_("Invalid repository"), repository,))) return 1 try: webserv = _get_service(entropy_client, repository, tx_cb = True) except WebService.UnsupportedService: print_info( "[%s] %s." % ( darkgreen(repository), blue(_("Repository does not support Entropy Services.")), ) ) return 1 username = webserv.get_credentials() if (username is not None) and not force: print_info( "[%s] %s %s. %s." % ( darkgreen(repository), blue(_("Already logged in as")), bold(login_data[0]), blue(_("Please logout first")) ) ) return 0 elif (username is not None) and force: webserv.remove_credentials(repository) def fake_callback(*args, **kwargs): return True # use input box to read login input_params = [ ('username', _('Username'), fake_callback, False), ('password', _('Password'), fake_callback, True) ] login_data = entropy_client.input_box( "%s %s %s" % ( _('Please login against'), repository, _('repository'),), input_params, cancel_button = True ) if not login_data: print_warning( "[%s] %s" % ( darkgreen(repository), blue(_("Login aborted. Not logged in.")), ) ) return 1 username, password = login_data['username'], login_data['password'] webserv.add_credentials(username, password) try: webserv.validate_credentials() except WebService.AuthenticationFailed: print_warning( "[%s] %s" % ( darkgreen(repository), blue(_("Authentication error. Not logged in.")), ) ) return 1 except WebService.RequestError: print_warning( "[%s] %s" % ( darkgreen(repository), blue(_("Communication error. Not logged in.")), ) ) return 1 print_info( "[%s:uid:%s] %s: %s." % ( darkgreen(repository), etpConst['uid'], blue(_("Successfully logged in as")), bold(username) ) ) print_info( "%s." % ( blue(_("From now on, any UGC action will be committed as this user")) ) ) return 0 def _ugc_logout(entropy_client, repository): if repository not in entropy_client.repositories(): print_error(red("%s: %s." % (_("Invalid repository"), repository,))) return 1 try: webserv = _get_service(entropy_client, repository) except WebService.UnsupportedService: print_info( "[%s] %s" % ( darkgreen(repository), blue(_("Repository does not support Entropy Services.")), ) ) return 1 username = webserv.get_credentials() if username is None: print_info( "[%s] %s" % ( darkgreen(repository), blue(_("Not logged in.")), ) ) return 0 webserv.remove_credentials() print_info( "[%s] %s %s %s" % ( darkgreen(repository), blue(_("User")), bold(username), blue(_("has been logged out.")), ) ) return 0 def _ugc_votes(entropy_client, options): rc = -10 repository = options[0] options = options[1:] if not options: return rc cmd = options[0] options = options[1:] if not options: return rc pkgkey = options[0] options = options[1:] if repository not in entropy_client.repositories(): print_error(red("%s: %s." % (_("Invalid repository"), repository,))) return 1 try: webserv = _get_service(entropy_client, repository) except WebService.UnsupportedService: print_info( "[%s] %s" % ( darkgreen(repository), blue(_("Repository does not support Entropy Services.")), ) ) return 1 username = webserv.get_credentials() if username is None: print_info( "[%s] %s" % ( darkgreen(repository), blue(_("Not logged in, please login first.")), ) ) return 0 rc = 0 if cmd == "get": try: vote = webserv.get_votes([pkgkey], cache = False)[pkgkey] except WebService.WebServiceException as err: print_error( "[%s] %s: %s" % ( darkred(pkgkey), blue(_("UGC error")), err, ) ) return 1 _show_vote(vote, repository, pkgkey) elif cmd == "add": print_info(" %s [%s] %s" % ( bold("@@"), purple(pkgkey), blue(_("add vote")), ) ) def mycb(s): return s input_data = [('vote', darkred(_("Insert your vote (from 1 to 5)")), mycb, False)] data = entropy_client.input_box( blue("%s") % (_("Entropy UGC vote submission"),), input_data, cancel_button = True) if not data: return 1 elif not isinstance(data, dict): return 1 elif 'vote' not in data: return 1 elif not data['vote']: return 1 try: vote = int(data['vote']) if vote not in ClientWebService.VALID_VOTES: raise ValueError() except ValueError: print_error( "[%s] %s: %s: %s" % ( darkred(pkgkey), blue(_("UGC error")), _("invalid vote, must be in range"), " ".join([str(x) for x in ClientWebService.VALID_VOTES]), ) ) return 1 print_info(" %s [%s] %s:" % ( bold("@@"), purple(pkgkey), blue(_("Please review your submission")), ) ) print_info(" %s: %s" % ( darkred(_("Vote")), blue(str(vote)), ) ) rc = entropy_client.ask_question(_("Do you want to submit?")) if rc != _("Yes"): return 1 try: voted = webserv.add_vote(pkgkey, vote, clear_available_cache = True) except WebService.WebServiceException as err: print_error( "[%s] %s: %s" % ( darkred(pkgkey), blue(_("UGC error")), err, ) ) return 1 if not voted: print_error( "[%s] %s: %s" % ( darkred(pkgkey), blue(_("UGC error")), _("already voted"), ) ) return 1 else: print_info("[%s] %s" % ( purple(pkgkey), blue(_("vote added, thank you!")), ) ) _ugc_votes(entropy_client, [repository, "get", pkgkey]) def _ugc_documents(entropy_client, options): repository = options[0] options = options[1:] if not options: return -10 cmd = options[0] options = options[1:] if not options: return -10 try: webserv = _get_service(entropy_client, repository, tx_cb = True) except WebService.UnsupportedService: print_info( "[%s] %s" % ( darkgreen(repository), blue(_("Repository does not support Entropy Services.")), ) ) return 1 if cmd == "get": pkgkey = options.pop(0) docs = [] docs_offset = 0 while True: try: docs_list = webserv.get_documents([pkgkey], cache = False, offset = docs_offset)[pkgkey] except WebService.WebServiceException as err: print_error( "[%s] %s: %s" % ( darkred(pkgkey), blue(_("UGC error")), err, ) ) return 1 if docs_list is None: print_error( "[%s] %s: %s, %s" % ( darkred(pkgkey), blue(_("UGC error")), data, err_string, ) ) return 1 docs.extend(docs_list) if not docs_list.has_more(): break docs_offset += len(docs_list) try: downloads = webserv.get_downloads([pkgkey], cache = False)[pkgkey] except WebService.WebServiceException as err: print_error( "[%s] %s: %s" % ( darkred(pkgkey), blue(_("UGC error")), err, ) ) return 1 for doc in docs: _show_document(doc, repository, pkgkey) if docs: print_info(" %s %s: %s" % ( darkred("@@"), blue(_("Number of downloads")), downloads, ) ) else: print_info(" %s %s" % ( darkred("@@"), blue(_("No User Generated Content available.")), ) ) return 0 elif cmd == "add": pkgkey = options.pop(0) username = webserv.get_credentials() if username is None: print_info( "[%s] %s" % ( darkgreen(repository), blue(_("Not logged in, please login first.")), ) ) return 0 print_info(" %s [%s|%s] %s" % ( bold("@@"), darkgreen(str(repository)), purple(str(pkgkey)), blue(_("Add document")), ) ) valid_types = { ('c', _('text comment')): Document.COMMENT_TYPE_ID, ('o', _('icon')): Document.ICON_TYPE_ID, ('f', _('simple file')): Document.FILE_TYPE_ID, ('i', _('simple image')): Document.IMAGE_TYPE_ID, ('y', _('video')): Document.VIDEO_TYPE_ID, } upload_needed_types = [ Document.FILE_TYPE_ID, Document.IMAGE_TYPE_ID, Document.ICON_TYPE_ID, Document.VIDEO_TYPE_ID ] my_quick_types = [x[0] for x in valid_types] def mycb(s): return s def path_cb(s): return os.access(s, os.R_OK) and os.path.isfile(s) def types_cb(s): return s in my_quick_types input_data = [ ('title', darkred(_("Insert document title")), mycb, False), ('description', darkred(_("Insert document description/comment")), mycb, False), ('keywords', darkred(_("Insert document's keywords (space separated)")), mycb, False), ('type', "%s [%s]" % (darkred(_("Choose document type")), ', '.join(["(%s) %s" % (brown(x[0]), darkgreen(x[1]),) for x \ in valid_types])), types_cb, False), ] data = entropy_client.input_box( blue("%s") % (_("Entropy UGC document submission"),), input_data, cancel_button = True) if not data: return 1 elif not isinstance(data, dict): return 1 doc_type = None for myshort, mylong in valid_types: if data['type'] == myshort: doc_type = (myshort, mylong) data['type'] = valid_types.get((myshort, mylong,)) break data['path'] = None if data['type'] in upload_needed_types: input_data = [('path', darkred(_("Insert document path")), path_cb, False)] u_data = entropy_client.input_box( blue("%s") % (_("Entropy UGC document submission"),), input_data, cancel_button = True) if not u_data: return 1 elif not isinstance(data, dict): return 1 data['path'] = u_data['path'] keywords = ', '.join(data['keywords'].split()) # verify print_info(" %s [%s] %s:" % ( bold("@@"), purple(pkgkey), blue(_("Please review your submission")), ) ) print_info(" %s: %s" % ( darkred(_("Title")), blue(data['title']), ) ) print_info(" %s: %s" % ( darkred(_("Description")), blue(data['description']), ) ) print_info(" %s: %s" % ( darkred(_("Keywords")), blue(keywords), ) ) if data['path'] != None: print_info(" %s: %s" % ( darkred(_("Document path")), blue(data['path']), ) ) print_info(" %s: (%s) %s" % ( darkred(_("Document type")), darkred(doc_type[0]), blue(doc_type[1]), ) ) rc = entropy_client.ask_question(_("Do you want to submit?")) if rc != _("Yes"): return 1 doc_factory = DocumentFactory(repository) doc = None doc_f = None doc_type = data['type'] try: if doc_type == Document.COMMENT_TYPE_ID: doc = doc_factory.comment(username, data['description'], data['title'], data['keywords']) elif doc_type == Document.ICON_TYPE_ID: doc_f = open(data['path'], "rb") doc = doc_factory.icon(username, doc_f, data['title'], data['description'], data['keywords']) elif doc_type == Document.FILE_TYPE_ID: doc_f = open(data['path'], "rb") doc = doc_factory.file(username, doc_f, data['title'], data['description'], data['keywords']) elif doc_type == Document.IMAGE_TYPE_ID: doc_f = open(data['path'], "rb") doc = doc_factory.image(username, doc_f, data['title'], data['description'], data['keywords']) elif doc_type == Document.VIDEO_TYPE_ID: doc_f = open(data['path'], "rb") doc = doc_factory.video(username, doc_f, data['title'], data['description'], data['keywords']) except AssertionError as err: print_error( "[%s] %s: %s" % ( darkred(pkgkey), blue(_("Invalid document")), err, ) ) if doc_f is not None: doc_f.close() return 1 try: new_doc = webserv.add_document(pkgkey, doc) except WebService.WebServiceException as err: print_error( "[%s] %s: %s" % ( darkred(pkgkey), blue(_("UGC error")), err, ) ) return 1 finally: if doc_f is not None: doc_f.close() print_info(" %s [%s|id:%s] %s" % ( bold("@@"), purple(pkgkey), new_doc.document_id(), blue(_("Document added, thank you!")), ) ) return 0 elif cmd == "remove": print_info(" %s [%s] %s" % ( bold("@@"), darkgreen(repository), blue(_("Documents removal")), ) ) print_info(" %s [%s] %s:" % ( bold("@@"), darkgreen(repository), blue(_("Please review your submission")), ) ) print_info(" %s: %s" % ( darkred(_("Document identifiers")), blue(', '.join(options)), ) ) identifiers = [] for opt in options: try: identifiers.append(int(opt)) except ValueError: pass if not identifiers: print_error( "[%s] %s: %s, %s" % ( darkgreen(repository), blue(_("UGC error")), _("No valid identifiers"), options, ) ) return 1 rc = entropy_client.ask_question(_("Would you like to review them?")) if rc == _("Yes"): try: docs_map = webserv.get_documents_by_id(identifiers, cache = False) except WebService.WebServiceException as err: print_error( "[%s] %s: %s" % ( darkred(str(identifiers)), blue(_("UGC error")), err, ) ) return 1 for pkgkey, doc in docs_map.items(): if doc is None: # doesn't exist continue _show_document(doc, repository, pkgkey) rc = entropy_client.ask_question( _("Would you like to continue with the removal?")) if rc != _("Yes"): return 1 try: docs_map = webserv.get_documents_by_id(identifiers, cache = False) except WebService.WebServiceException as err: print_error( "[%s] %s: %s" % ( darkred(str(identifiers)), blue(_("UGC error")), err, ) ) return 1 for identifier in identifiers: doc = docs_map[identifier] if doc is None: print_error( "[%s] %s: %s" % ( darkred(str(identifier)), blue(_("UGC error")), _("cannot get the requested Document"), ) ) continue try: docs_map = webserv.remove_document(identifier) except WebService.WebServiceException as err: print_error( "[%s] %s: %s" % ( darkred(str(identifiers)), blue(_("UGC error")), err, ) ) continue print_info( "[%s] %s: %s" % ( darkred(str(identifier)), blue(_("UGC status")), _("removed successfully"), ) ) return 0 return -10 def _show_document(doc, repository, pkgkey): title = const_convert_to_unicode(doc[Document.DOCUMENT_TITLE_ID]) if not title: title = _("No title") title = darkgreen(title) ts = doc.document_timestamp() ts = entropy.tools.convert_unix_time_to_human_time(ts) print_info(" %s [%s|%s|%s|%s|%s|%s]" % ( bold("@@"), bold(str(doc.document_id())), darkred(str(doc.document_type())), darkgreen(repository), purple(pkgkey), blue(doc[DocumentFactory.DOCUMENT_USERNAME_ID]), darkgreen(ts), ) ) print_info("\t%s: %s" % ( blue(_("Title")), title, ) ) if const_isstring(doc.document_data()): text = doc.document_data() else: text = doc.document_data().tostring() text = const_convert_to_unicode(text) _my_formatted_print(text, "\t%s: " % (blue(_("Content")),), "\t") print_info("\t%s: %s" % ( blue(_("Keywords")), doc.document_keywords(), ) ) url = doc.document_url() if url is not None: print_info("\t%s: %s" % ( blue(_("Download")), url, ) ) def _show_vote(vote, repository, pkgkey): if vote is None: vote = _("no votes") else: vote = str(vote) print_info(" %s [%s] %s: %s" % ( bold("@@"), purple(pkgkey), darkred(_("current package vote")), darkgreen(vote), ) ) def _my_formatted_print(data,header, reset_columns, min_chars = 25, color = None): if isinstance(data, set): mydata = list(data) elif not isinstance(data, list): mydata = data.split() else: mydata = data fcount = 0 desc_text = header for x in mydata: fcount += len(x) if color: desc_text += color(x)+" " else: desc_text += x+" " if fcount > min_chars: fcount = 0 print_info(desc_text) desc_text = reset_columns if fcount > 0: print_info(desc_text)