1
2 '''
3 # DESCRIPTION:
4 # Entropy Object Oriented Interface
5
6 Copyright (C) 2007-2009 Fabio Erculiani
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 '''
22
23 from __future__ import with_statement
24 import os
25 import time
26 import subprocess
27 import shutil
28 from entropy.services.skel import RemoteDatabase
29 from entropy.exceptions import *
30 from entropy.const import etpConst, etpUi, etpCache, const_setup_perms, const_set_chmod, const_setup_file
31 from entropy.output import brown, bold, blue
32 from entropy.i18n import _
33
35
36 SQL_TABLES = {
37 'entropy_base': """
38 CREATE TABLE `entropy_base` (
39 `idkey` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
40 `key` VARCHAR( 255 ) collate utf8_bin NOT NULL,
41 KEY `key` (`key`)
42 );
43 """,
44 'entropy_votes': """
45 CREATE TABLE `entropy_votes` (
46 `idvote` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
47 `idkey` INT UNSIGNED NOT NULL,
48 `userid` INT UNSIGNED NOT NULL,
49 `vdate` DATE NOT NULL,
50 `vote` TINYINT NOT NULL,
51 `ts` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
52 FOREIGN KEY (`idkey`) REFERENCES `entropy_base` (`idkey`)
53 );
54 """,
55 'entropy_user_scores': """
56 CREATE TABLE `entropy_user_scores` (
57 `userid` INT UNSIGNED NOT NULL PRIMARY KEY,
58 `score` INT UNSIGNED NOT NULL DEFAULT 0
59 );
60 """,
61 'entropy_downloads': """
62 CREATE TABLE `entropy_downloads` (
63 `iddownload` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
64 `idkey` INT UNSIGNED NOT NULL,
65 `ddate` DATE NOT NULL,
66 `count` INT UNSIGNED NULL DEFAULT '0',
67 KEY `idkey` (`idkey`,`ddate`),
68 KEY `idkey_2` (`idkey`),
69 FOREIGN KEY (`idkey`) REFERENCES `entropy_base` (`idkey`)
70 );
71 """,
72 'entropy_downloads_data': """
73 CREATE TABLE `entropy_downloads_data` (
74 `iddownload` INT UNSIGNED NOT NULL,
75 `ip_address` VARCHAR(40) NULL DEFAULT '',
76 `entropy_ip_locations_id` INT UNSIGNED NULL DEFAULT 0,
77 FOREIGN KEY (`iddownload`) REFERENCES `entropy_downloads` (`iddownload`)
78 );
79 """,
80 'entropy_docs': """
81 CREATE TABLE `entropy_docs` (
82 `iddoc` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
83 `idkey` INT UNSIGNED NOT NULL,
84 `userid` INT UNSIGNED NOT NULL,
85 `username` VARCHAR( 255 ),
86 `iddoctype` TINYINT NOT NULL,
87 `ddata` TEXT NOT NULL,
88 `title` VARCHAR( 512 ),
89 `description` VARCHAR( 4000 ),
90 `ts` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
91 KEY `idkey` (`idkey`),
92 KEY `userid` (`userid`),
93 KEY `idkey_2` (`idkey`,`userid`,`iddoctype`),
94 KEY `title` (`title`(333)),
95 KEY `description` (`description`(333)),
96 FOREIGN KEY (`idkey`) REFERENCES `entropy_base` (`idkey`)
97 );
98 """,
99 'entropy_doctypes': """
100 CREATE TABLE `entropy_doctypes` (
101 `iddoctype` TINYINT NOT NULL PRIMARY KEY,
102 `description` TEXT NOT NULL
103 );
104 """,
105 'entropy_docs_keywords': """
106 CREATE TABLE `entropy_docs_keywords` (
107 `iddoc` INT UNSIGNED NOT NULL,
108 `keyword` VARCHAR( 100 ),
109 KEY `keyword` (`keyword`),
110 FOREIGN KEY (`iddoc`) REFERENCES `entropy_docs` (`iddoc`)
111 );
112 """,
113 'entropy_distribution_usage': """
114 CREATE TABLE `entropy_distribution_usage` (
115 `entropy_distribution_usage_id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
116 `entropy_branches_id` INT NOT NULL,
117 `entropy_release_strings_id` INT NOT NULL,
118 `ts` TIMESTAMP ON UPDATE CURRENT_TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
119 `ip_address` VARCHAR( 15 ),
120 `entropy_ip_locations_id` INT UNSIGNED NULL DEFAULT 0,
121 `creation_date` DATETIME DEFAULT NULL,
122 `hits` INT UNSIGNED NULL DEFAULT 0,
123 FOREIGN KEY (`entropy_branches_id`) REFERENCES `entropy_branches` (`entropy_branches_id`),
124 FOREIGN KEY (`entropy_release_strings_id`) REFERENCES `entropy_release_strings` (`entropy_release_strings_id`),
125 KEY `ip_address` (`ip_address`),
126 KEY `entropy_ip_locations_id` (`entropy_ip_locations_id`)
127 );
128 """,
129 'entropy_hardware_usage': """
130 CREATE TABLE `entropy_hardware_usage` (
131 `entropy_hardware_usage_id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
132 `entropy_distribution_usage_id` INT UNSIGNED NOT NULL,
133 `entropy_hardware_hash` VARCHAR ( 64 ),
134 FOREIGN KEY (`entropy_distribution_usage_id`) REFERENCES `entropy_distribution_usage` (`entropy_distribution_usage_id`)
135 );
136 """,
137
138
139
140
141
142
143
144
145 'entropy_branches': """
146 CREATE TABLE `entropy_branches` (
147 `entropy_branches_id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
148 `entropy_branch` VARCHAR( 100 )
149 );
150 """,
151 'entropy_release_strings': """
152 CREATE TABLE `entropy_release_strings` (
153 `entropy_release_strings_id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
154 `release_string` VARCHAR( 255 )
155 );
156 """,
157 'entropy_ip_locations': """
158 CREATE TABLE `entropy_ip_locations` (
159 `entropy_ip_locations_id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
160 `ip_latitude` FLOAT( 8,5 ),
161 `ip_longitude` FLOAT( 8,5 ),
162 KEY `ip_locations_lat_lon` (`ip_latitude`,`ip_longitude`)
163 );
164 """,
165 }
166 VOTE_RANGE = etpConst['ugc_voterange']
167 VIRUS_CHECK_EXEC = '/usr/bin/clamscan'
168 VIRUS_CHECK_ARGS = []
169 gdata = None
170 YouTube = None
171 YouTubeService = None
172 entropy_docs_title_len = 512
173 entropy_docs_description_len = 4000
174 entropy_docs_keyword_len = 100
175 COMMENTS_SCORE_WEIGHT = 5
176 DOCS_SCORE_WEIGHT = 10
177 VOTES_SCORE_WEIGHT = 2
178 STATS_MAP = {
179 'installer': "installer",
180 }
181
182 '''
183 dependencies:
184 dev-python/gdata
185 '''
186 - def __init__(self, connection_data, store_path, store_url = ''):
187 import entropy.dump as dumpTools
188 import entropy.tools as entropyTools
189 from entropy.misc import EntropyGeoIP
190 self.EntropyGeoIP = EntropyGeoIP
191 self.entropyTools, self.dumpTools = entropyTools, dumpTools
192 self.store_url = store_url
193 self.FLOOD_INTERVAL = 30
194 self.DOC_TYPES = etpConst['ugc_doctypes'].copy()
195 self.UPLOADED_DOC_TYPES = [
196 self.DOC_TYPES['image'],
197 self.DOC_TYPES['generic_file']
198 ]
199 RemoteDatabase.__init__(self)
200 self.set_connection_data(connection_data)
201 self.connect()
202 self.initialize_tables()
203 self.initialize_doctypes()
204 self.setup_store_path(store_path)
205 from entropy.core import SystemSettings
206 self.__system_settings = SystemSettings()
207 self.system_name = self.__system_settings['system']['name']
208 from datetime import datetime
209 self.datetime = datetime
210 try:
211 import gdata
212 import gdata.youtube
213 import gdata.youtube.service
214 self.gdata = gdata
215 self.YouTube = gdata.youtube
216 self.YouTubeService = gdata.youtube.service
217 except ImportError:
218 pass
219
220 self.cached_results = {
221
222 'get_ugc_alldownloads': (self.get_ugc_alldownloads, [], {}, 86400),
223
224 'get_total_downloads_count': (self.get_total_downloads_count, [], {}, 7200),
225 }
226
228 return int(time.time())
229
231 for cache_item in self.cached_results:
232 fdata = self.cached_results.get(cache_item)
233 if fdata == None: return
234 func, args, kwargs, exp_time = fdata
235 key = self.get_cache_item_key(cache_item)
236 r = func(*args,**kwargs)
237 self.dumpTools.dumpobj(key, r)
238
240 return os.path.join(etpCache['ugc_srv_cache'],cache_item)
241
243 if not self.cached_results.get(cache_item): return None
244 key = self.get_cache_item_key(cache_item)
245 self.dumpTools.dumpobj(key, r)
246
248 geoip_dbpath = self.connection_data.get('geoip_dbpath','')
249 if os.path.isfile(geoip_dbpath) and os.access(geoip_dbpath,os.R_OK):
250 try:
251 geo = self.EntropyGeoIP(geoip_dbpath)
252 return geo.get_geoip_record_from_ip(ip_address)
253 except:
254 pass
255
256
258 fdata = self.cached_results.get(cache_item)
259 if fdata == None: return None
260 func, args, kwargs, exp_time = fdata
261
262 key = self.get_cache_item_key(cache_item)
263 cur_time = self.get_current_time()
264 cache_time = self.dumpTools.getobjmtime(key)
265 if (cache_time + exp_time) < cur_time:
266
267 return None
268 return self.dumpTools.loadobj(key)
269
271 path = os.path.realpath(path)
272 if not os.path.isabs(path):
273 raise PermissionDenied('PermissionDenied: %s' % (_("not a valid directory path"),))
274 if not os.path.isdir(path):
275 try:
276 os.makedirs(path)
277 except OSError, e:
278 raise PermissionDenied('PermissionDenied: %s' % (e,))
279 if etpConst['entropygid'] != None:
280 const_setup_perms(path,etpConst['entropygid'])
281 self.STORE_PATH = path
282
292
298
300 self.check_connection()
301 rows = self.execute_query('SELECT `iddoctype` FROM entropy_doctypes WHERE `iddoctype` = %s', (iddoctype,))
302 if rows:
303 return True
304 return False
305
307 self.check_connection()
308 rows = self.execute_query('SELECT `idkey` FROM entropy_base WHERE `key` = %s', (key,))
309 if rows:
310 return True
311 return False
312
314 self.check_connection()
315 rows = self.execute_query('SELECT `iddoc` FROM entropy_docs WHERE `iddoc` = %s', (iddoc,))
316 if rows:
317 return True
318 return False
319
324
331
339
346
353
360
362 entropy_ip_locations_id = 0
363 geo_data = self._get_geoip_data_from_ip_address(ip_addr)
364 if isinstance(geo_data,dict):
365 ip_lat = geo_data.get('latitude')
366 ip_long = geo_data.get('longitude')
367 if isinstance(ip_lat,float) and isinstance(ip_long,float):
368 ip_lat = round(ip_lat,5)
369 ip_long = round(ip_long,5)
370 entropy_ip_locations_id = self.get_entropy_ip_locations_id(ip_lat, ip_long)
371 if entropy_ip_locations_id == -1:
372 entropy_ip_locations_id = self.insert_entropy_ip_locations_id(ip_lat, ip_long)
373 return entropy_ip_locations_id
374
376 self.check_connection()
377 self.execute_query('UPDATE entropy_downloads SET `count` = `count`+1 WHERE `iddownload` = %s', (iddownload,))
378 if do_commit: self.commit()
379 return iddownload
380
382 entropy_ip_locations_id = self.handle_entropy_ip_locations_id(ip_addr)
383 mydata = [(x,ip_addr,entropy_ip_locations_id,) for x in iddownloads]
384 self.execute_many('INSERT INTO entropy_downloads_data VALUES (%s,%s,%s)', mydata)
385 if do_commit: self.commit()
386
388 mytime = time.time()
389 mydate = self.datetime.fromtimestamp(mytime)
390 mydate = self.datetime(mydate.year,mydate.month,mydate.day)
391 return mydate
392
394 mytime = time.time()
395 mydate = self.datetime.fromtimestamp(mytime)
396 mydate = self.datetime(mydate.year,mydate.month,mydate.day,mydate.hour,mydate.minute,mydate.second)
397 return mydate
398
400 self.check_connection()
401 idkey = self.handle_pkgkey(key)
402 self.execute_query('SELECT `iddownload` FROM entropy_downloads WHERE `idkey` = %s AND `ddate` = %s', (idkey,ddate,))
403 data = self.fetchone()
404 if data:
405 return data['iddownload']
406 return -1
407
409 self.check_connection()
410 self.execute_query('SELECT `idkey` FROM entropy_base WHERE `key` = %s', (key,))
411 data = self.fetchone()
412 if data:
413 return data['idkey']
414 return -1
415
417 self.check_connection()
418 self.execute_query('SELECT `iddoctype` FROM entropy_docs WHERE `iddoc` = %s', (iddoc,))
419 data = self.fetchone()
420 if data:
421 return data['iddoctype']
422 return -1
423
425 self.check_connection()
426 self.execute_query('SELECT `entropy_branches_id` FROM entropy_branches WHERE `entropy_branch` = %s', (branch,))
427 data = self.fetchone()
428 if data:
429 return data['entropy_branches_id']
430 return -1
431
433 self.check_connection()
434 self.execute_query('SELECT `entropy_release_strings_id` FROM entropy_release_strings WHERE `release_string` = %s', (release_string,))
435 data = self.fetchone()
436 if data:
437 return data['entropy_release_strings_id']
438 return -1
439
441 self.check_connection()
442 self.execute_query("""
443 SELECT `entropy_ip_locations_id` FROM
444 entropy_ip_locations WHERE
445 `ip_latitude` = %s AND `ip_longitude` = %s""", (ip_latitude,ip_longitude,))
446 data = self.fetchone()
447 if data:
448 return data['entropy_ip_locations_id']
449 return -1
450
456
469
471 self.execute_query('SELECT `keyword` FROM entropy_docs_keywords WHERE `iddoc` = %s order by `keyword`', (iddoc,))
472 return [x.get('keyword') for x in self.fetchall() if x.get('keyword')]
473
484
495
503
533
535 self.check_connection()
536 self.execute_query("""
537 SELECT avg(entropy_votes.`vote`) as avg_vote FROM entropy_votes,entropy_base WHERE
538 entropy_base.`key` = %s AND
539 entropy_base.idkey = entropy_votes.idkey""", (pkgkey,))
540 data = self.fetchone() or {}
541 avg_vote = data.get('avg_vote')
542 if not avg_vote:
543 return 0.0
544 return avg_vote
545
547
548
549 cache_item = 'get_ugc_allvotes'
550 cached = self.get_cached_result(cache_item)
551 if cached != None:
552 return cached
553
554 self.check_connection()
555 self.execute_query("""
556 SELECT entropy_base.`key` as `vkey`,avg(entropy_votes.vote) as `avg_vote` FROM
557 entropy_votes,entropy_base WHERE
558 entropy_votes.`idkey` = entropy_base.`idkey` GROUP BY entropy_base.`key`""")
559 vote_data = dict( ((x['vkey'], x['avg_vote'],) for x in self.fetchall()) )
560
561
562 self.cache_result(cache_item, vote_data)
563 return vote_data
564
566 self.check_connection()
567
568 self.execute_query("""
569 SELECT SQL_CACHE sum(entropy_downloads.`count`) as `tot_downloads` FROM
570 entropy_downloads,entropy_base WHERE entropy_base.key = %s AND
571 entropy_base.idkey = entropy_downloads.idkey""", (pkgkey,))
572
573 data = self.fetchone() or {}
574 downloads = data.get('tot_downloads')
575 if not downloads:
576 return 0
577 return downloads
578
580
581 cache_item = 'get_ugc_alldownloads'
582 cached = self.get_cached_result(cache_item)
583 if cached != None: return cached
584
585 self.check_connection()
586 self.execute_query("""
587 SELECT SQL_CACHE entropy_base.key as vkey, tot_downloads from entropy_base,
588 (SELECT idkey as idp1, sum(entropy_downloads.`count`) AS `tot_downloads` FROM
589 entropy_downloads GROUP BY entropy_downloads.`idkey`) as tmp where idkey = tmp.idp1;
590 """)
591 down_data = dict( ((x['vkey'], x['tot_downloads'],) for x in self.fetchall()) )
592
593
594 self.cache_result(cache_item, down_data)
595 return down_data
596
602
611
613 self.check_connection()
614 self.execute_query('SELECT count(`iddoc`) as comments FROM entropy_docs WHERE `iddoctype` != %s', (self.DOC_TYPES['comments'],))
615 data = self.fetchone() or {}
616 comments = data.get('comments')
617 if not comments:
618 return 0
619 return comments
620
622 self.check_connection()
623 self.execute_query('SELECT count(`idvote`) as votes FROM entropy_votes')
624 data = self.fetchone() or {}
625 votes = data.get('votes')
626 if not votes:
627 return 0
628 return votes
629
631
632
633 cache_item = 'get_total_downloads_count'
634 cached = self.get_cached_result(cache_item)
635 if cached != None: return cached
636
637 self.check_connection()
638 self.execute_query('SELECT SQL_CACHE sum(entropy_downloads.`count`) as downloads FROM entropy_downloads')
639 data = self.fetchone() or {}
640 downloads = data.get('downloads', 0)
641 if not downloads:
642 return 0
643 result = int(downloads)
644
645
646 self.cache_result(cache_item, result)
647 return result
648
650 self.check_connection()
651 self.execute_query('SET @row = 0')
652 self.execute_query("""
653 SELECT Row, col_a FROM (SELECT @row := @row + 1 AS Row, userid AS col_a FROM
654 entropy_user_scores ORDER BY score DESC) As derived1 WHERE col_a = %s""", (userid,))
655 data = self.fetchone() or {}
656 ranking = data.get('Row', 0)
657 if not ranking:
658 return 0
659 return ranking
660
662
663
664 cache_item = 'get_users_scored_count'
665 cached = self.get_cached_result(cache_item)
666 if cached != None:
667 return cached
668
669 self.check_connection()
670 self.execute_query('SELECT SQL_CACHE count(`userid`) as mycount FROM entropy_user_scores')
671 data = self.fetchone() or {}
672 count = data.get('mycount', 0)
673 if not count:
674 return 0
675
676
677 self.cache_result(cache_item, count)
678 return count
679
681 self.check_connection()
682 rows = self.execute_query('SELECT `userid` FROM entropy_user_scores WHERE `userid` = %s', (userid,))
683 if rows:
684 return True
685 return False
686
694
704
713
715 self.check_connection()
716 limit_string = ''
717 if count:
718 limit_string += ' LIMIT %s,%s' % (offset,count,)
719 self.execute_query('SELECT SQL_CALC_FOUND_ROWS *, userid, score FROM entropy_user_scores ORDER BY score DESC' + limit_string)
720 data = self.fetchall()
721
722 self.execute_query('SELECT FOUND_ROWS() as count')
723 rdata = self.fetchone() or {}
724 found_rows = rdata.get('count', 0)
725 if found_rows is None:
726 found_rows = 0
727
728 return found_rows, data
729
731 self.check_connection()
732 self.execute_query('SELECT avg(`vote`) as vote_avg FROM entropy_votes WHERE `userid` = %s', (userid,))
733 data = self.fetchone() or {}
734 vote_avg = data.get('vote_avg', 0.0)
735 if not vote_avg:
736 return 0.0
737 return round(float(vote_avg), 2)
738
740 self.check_connection()
741 self.execute_query("""
742 SELECT * FROM entropy_docs,entropy_base WHERE
743 entropy_docs.`userid` = %s AND
744 entropy_base.idkey = entropy_docs.idkey ORDER BY entropy_base.`key`""", (userid,))
745 return self.fetchall()
746
749
752
757
759 self.check_connection()
760 self.execute_query('SELECT * FROM entropy_docs WHERE `userid` = %s AND `iddoctype` '+doctype_sql_cmp+' %s', (userid,doctype,))
761 return self.fetchall()
762
764 self.check_connection()
765 self.execute_query('SELECT count(`iddoc`) as docs FROM entropy_docs WHERE `userid` = %s AND `iddoctype` '+doctype_sql_cmp+' %s', (userid,doctype,))
766 data = self.fetchone() or {}
767 docs = data.get('docs', 0)
768 if docs is None:
769 docs = 0
770 return docs
771
774
777
780
783
786
788 self.check_connection()
789 self.execute_query('SELECT count(`idvote`) as votes FROM entropy_votes WHERE `userid` = %s', (userid,))
790 data = self.fetchone() or {}
791 votes = data.get('votes', 0)
792 if votes is None:
793 votes = 0
794 return votes
795
809
818
819 - def search_pkgkey_items(self, pkgkey_string, iddoctypes = None, results_offset = 0, results_limit = 30, order_by = None):
820 self.check_connection()
821
822 if iddoctypes == None:
823 iddoctypes = [self.DOC_TYPES[x] for x in self.DOC_TYPES]
824 iddoctypes = "("+', '.join([str(self.DOC_TYPES[x]) for x in self.DOC_TYPES])+")"
825 myterm = "%"+pkgkey_string+"%"
826
827 search_params = [myterm,results_offset,results_limit]
828
829 order_by_string = ''
830 if order_by == "key":
831 order_by_string = 'ORDER BY entropy_base.`key`'
832 elif order_by == "username":
833 order_by_string = 'ORDER BY entropy_docs.`username`'
834 elif order_by == "vote":
835 order_by_string = 'ORDER BY avg_vote DESC'
836 elif order_by == "downloads":
837 order_by_string = 'ORDER BY tot_downloads DESC'
838
839 self.execute_query("""
840 SELECT SQL_CALC_FOUND_ROWS *, avg(entropy_votes.`vote`) as avg_vote,
841 sum(entropy_downloads.`count`) as `tot_downloads`,
842 entropy_user_scores.`score` as `score` FROM
843 entropy_docs,entropy_base,entropy_votes,entropy_downloads,entropy_user_scores WHERE
844 entropy_base.`key` LIKE %s AND
845 entropy_docs.`iddoctype` IN """+iddoctypes+""" AND
846 entropy_docs.`idkey` = entropy_base.`idkey` AND
847 entropy_votes.`idkey` = entropy_base.`idkey` AND
848 entropy_downloads.`idkey` = entropy_base.`idkey` AND
849 entropy_docs.`userid` = entropy_user_scores.`userid`
850 GROUP BY entropy_docs.`iddoc` """+order_by_string+""" LIMIT %s,%s""", search_params)
851
852 results = self.fetchall()
853 self.execute_query('SELECT FOUND_ROWS() as count')
854 data = self.fetchone() or {}
855 count = data.get('count', 0)
856 if count is None:
857 count = 0
858 return results, count
859
860 - def search_username_items(self, pkgkey_string, iddoctypes = None, results_offset = 0, results_limit = 30, order_by = None):
861 self.check_connection()
862
863 if iddoctypes == None:
864 iddoctypes = [self.DOC_TYPES[x] for x in self.DOC_TYPES]
865 iddoctypes = "("+', '.join([str(self.DOC_TYPES[x]) for x in self.DOC_TYPES])+")"
866 myterm = "%"+pkgkey_string+"%"
867
868 search_params = [myterm,results_offset,results_limit]
869
870 order_by_string = ''
871 if order_by == "key":
872 order_by_string = 'ORDER BY entropy_base.`key`'
873 elif order_by == "username":
874 order_by_string = 'ORDER BY entropy_docs.`username`'
875 elif order_by == "vote":
876 order_by_string = 'ORDER BY avg_vote DESC'
877 elif order_by == "downloads":
878 order_by_string = 'ORDER BY tot_downloads DESC'
879
880 self.execute_query("""
881 SELECT SQL_CALC_FOUND_ROWS *, avg(entropy_votes.`vote`) as avg_vote,
882 sum(entropy_downloads.`count`) as `tot_downloads`,
883 entropy_user_scores.`score` as `score` FROM
884 entropy_docs,entropy_base,entropy_votes,entropy_downloads,entropy_user_scores WHERE
885 entropy_docs.`username` LIKE %s AND entropy_docs.`iddoctype` IN """+iddoctypes+""" AND
886 entropy_docs.`idkey` = entropy_base.`idkey` AND
887 entropy_votes.`idkey` = entropy_base.`idkey` AND
888 entropy_downloads.`idkey` = entropy_base.`idkey` AND
889 entropy_docs.`userid` = entropy_user_scores.`userid`
890 GROUP BY entropy_docs.`iddoc` """+order_by_string+""" LIMIT %s,%s""", search_params)
891
892 results = self.fetchall()
893 self.execute_query('SELECT FOUND_ROWS() as count')
894 data = self.fetchone() or {}
895 count = data.get('count', 0)
896 if count is None:
897 count = 0
898 return results, count
899
900 - def search_content_items(self, pkgkey_string, iddoctypes = None, results_offset = 0, results_limit = 30, order_by = None):
901 self.check_connection()
902
903 if iddoctypes == None:
904 iddoctypes = [self.DOC_TYPES[x] for x in self.DOC_TYPES]
905 iddoctypes = "("+', '.join([str(self.DOC_TYPES[x]) for x in self.DOC_TYPES])+")"
906 myterm = "%"+pkgkey_string+"%"
907 search_params = [myterm,myterm,myterm,results_offset,results_limit]
908
909 order_by_string = ''
910 if order_by == "key":
911 order_by_string = 'ORDER BY entropy_base.`key`'
912 elif order_by == "username":
913 order_by_string = 'ORDER BY entropy_docs.`username`'
914 elif order_by == "vote":
915 order_by_string = 'ORDER BY avg_vote DESC'
916 elif order_by == "downloads":
917 order_by_string = 'ORDER BY tot_downloads DESC'
918
919 self.execute_query("""
920 SELECT SQL_CALC_FOUND_ROWS *, avg(entropy_votes.`vote`) as avg_vote,
921 sum(entropy_downloads.`count`) as `tot_downloads`,
922 entropy_user_scores.`score` as `score` FROM
923 entropy_docs,entropy_base,entropy_votes,entropy_downloads,entropy_user_scores WHERE
924 (entropy_docs.`title` LIKE %s OR entropy_docs.`description` LIKE %s OR entropy_docs.`ddata` LIKE %s) AND
925 entropy_docs.`iddoctype` IN """+iddoctypes+""" AND
926 entropy_docs.`idkey` = entropy_base.`idkey` AND
927 entropy_votes.`idkey` = entropy_base.`idkey` AND
928 entropy_downloads.`idkey` = entropy_base.`idkey` AND
929 entropy_docs.`userid` = entropy_user_scores.`userid`
930 GROUP BY entropy_docs.`iddoc` """+order_by_string+""" LIMIT %s,%s""", search_params)
931
932 results = self.fetchall()
933 self.execute_query('SELECT FOUND_ROWS() as count')
934 data = self.fetchone() or {}
935 count = data.get('count', 0)
936 if count is None:
937 count = 0
938 return results, count
939
940 - def search_keyword_items(self, keyword_string, iddoctypes = None, results_offset = 0, results_limit = 30, order_by = None):
941 self.check_connection()
942
943 if iddoctypes == None:
944 iddoctypes = [self.DOC_TYPES[x] for x in self.DOC_TYPES]
945 iddoctypes = "("+', '.join([str(self.DOC_TYPES[x]) for x in self.DOC_TYPES])+")"
946 myterm = "%"+keyword_string+"%"
947
948 search_params = [myterm,results_offset,results_limit]
949
950 order_by_string = ''
951 if order_by == "key":
952 order_by_string = 'ORDER BY entropy_base.`key`'
953 elif order_by == "username":
954 order_by_string = 'ORDER BY entropy_docs.`username`'
955 elif order_by == "vote":
956 order_by_string = 'ORDER BY avg_vote DESC'
957 elif order_by == "downloads":
958 order_by_string = 'ORDER BY tot_downloads DESC'
959
960 self.execute_query("""
961 SELECT SQL_CALC_FOUND_ROWS *, avg(entropy_votes.`vote`) as avg_vote,
962 sum(entropy_downloads.`count`) as `tot_downloads`,
963 entropy_user_scores.`score` as `score` FROM
964 entropy_docs,entropy_base,entropy_docs_keywords,entropy_votes,entropy_downloads,entropy_user_scores WHERE
965 entropy_docs_keywords.`keyword` LIKE %s AND
966 entropy_docs.`iddoctype` IN """+iddoctypes+""" AND
967 entropy_docs.`idkey` = entropy_base.`idkey` AND
968 entropy_docs_keywords.`iddoc` = entropy_docs.`iddoc` AND
969 entropy_votes.`idkey` = entropy_base.`idkey` AND
970 entropy_downloads.`idkey` = entropy_base.`idkey` AND
971 entropy_docs.`userid` = entropy_user_scores.`userid`
972 GROUP BY entropy_docs.`iddoc` """+order_by_string+""" LIMIT %s,%s""", search_params)
973
974 results = self.fetchall()
975 self.execute_query('SELECT FOUND_ROWS() as count')
976 data = self.fetchone() or {}
977 count = data.get('count', 0)
978 if count is None:
979 count = 0
980 return results, count
981
982 - def search_iddoc_item(self, iddoc_string, iddoctypes = None, results_offset = 0, results_limit = 30, order_by = None):
983 self.check_connection()
984
985 if iddoctypes == None:
986 iddoctypes = [self.DOC_TYPES[x] for x in self.DOC_TYPES]
987 iddoctypes = "("+', '.join([str(self.DOC_TYPES[x]) for x in self.DOC_TYPES])+")"
988 try:
989 myterm = int(iddoc_string)
990 except ValueError:
991 return [], 0
992
993 search_params = [myterm,results_offset,results_limit]
994
995 order_by_string = ''
996 if order_by == "key":
997 order_by_string = 'ORDER BY entropy_base.`key`'
998 elif order_by == "username":
999 order_by_string = 'ORDER BY entropy_docs.`username`'
1000 elif order_by == "vote":
1001 order_by_string = 'ORDER BY avg_vote DESC'
1002 elif order_by == "downloads":
1003 order_by_string = 'ORDER BY tot_downloads DESC'
1004
1005 self.execute_query("""
1006 SELECT SQL_CALC_FOUND_ROWS *, avg(entropy_votes.`vote`) as avg_vote,
1007 sum(entropy_downloads.`count`) as `tot_downloads`,
1008 entropy_user_scores.`score` as `score` FROM
1009 entropy_docs,entropy_base,entropy_votes,entropy_downloads,entropy_user_scores WHERE
1010 entropy_docs.`iddoc` = %s AND
1011 entropy_docs.`iddoctype` IN """+iddoctypes+""" AND
1012 entropy_docs.`idkey` = entropy_base.`idkey` AND
1013 entropy_votes.`idkey` = entropy_base.`idkey` AND
1014 entropy_downloads.`idkey` = entropy_base.`idkey` AND
1015 entropy_docs.`userid` = entropy_user_scores.`userid`
1016 GROUP BY entropy_docs.`iddoc` """+order_by_string+""" LIMIT %s,%s""", search_params)
1017
1018 results = self.fetchall()
1019 self.execute_query('SELECT FOUND_ROWS() as count')
1020 data = self.fetchone() or {}
1021 count = data.get('count', 0)
1022 if count is None:
1023 count = 0
1024 return results, count
1025
1031
1033 self.check_connection()
1034 self.execute_query('SELECT max(`ts`) as ts FROM entropy_docs WHERE `userid` = %s', (userid,))
1035 data = self.fetchone()
1036 if not data:
1037 return False
1038 elif not data.has_key('ts'):
1039 return False
1040 elif data['ts'] == None:
1041 return False
1042 delta = self.datetime.fromtimestamp(time.time()) - data['ts']
1043 if (delta.days == 0) and (delta.seconds <= self.FLOOD_INTERVAL):
1044 return True
1045 return False
1046
1047 - def insert_generic_doc(self, idkey, userid, username, doc_type, data, title, description, keywords, do_commit = False):
1048 self.check_connection()
1049
1050 title = title[:self.entropy_docs_title_len]
1051 description = description[:self.entropy_docs_description_len]
1052
1053
1054 flood_risk = self.insert_flood_control_check(userid)
1055 if flood_risk:
1056 return 'flooding detected'
1057
1058 self.execute_query('INSERT INTO entropy_docs VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s)',(
1059 None,
1060 idkey,
1061 userid,
1062 username,
1063 doc_type,
1064 data,
1065 title,
1066 description,
1067 None,
1068 )
1069 )
1070 if do_commit:
1071 self.commit()
1072 iddoc = self.lastrowid()
1073 self.insert_keywords(iddoc, keywords)
1074 self.update_user_score(userid)
1075 return iddoc
1076
1078 keywords = keywords.split(",")
1079 clean_keys = []
1080 for key in keywords:
1081 try:
1082 key = key.strip().split()[0]
1083 except IndexError:
1084 continue
1085 if not key: continue
1086 if not key.isalnum(): continue
1087 key = key[:self.entropy_docs_keyword_len]
1088 if key in clean_keys: continue
1089 clean_keys.append(key)
1090
1091 if not clean_keys:
1092 return
1093
1094 mydata = []
1095 for key in clean_keys:
1096 mydata.append((iddoc, key,))
1097
1098 self.execute_many('INSERT INTO entropy_docs_keywords VALUES (%s,%s)', mydata)
1099
1101 self.execute_query('DELETE FROM entropy_docs_keywords WHERE `iddoc` = %s',(iddoc,))
1102
1113
1131
1144
1145
1146 - def do_vote(self, pkgkey, userid, vote, do_commit = False):
1147 self.check_connection()
1148 idkey = self.handle_pkgkey(pkgkey)
1149 vote = int(vote)
1150 if vote not in self.VOTE_RANGE:
1151 vote = 3
1152 mydate = self.get_date()
1153 if self.has_user_already_voted(pkgkey, userid):
1154 return False
1155 self.execute_query('INSERT INTO entropy_votes VALUES (%s,%s,%s,%s,%s,%s)',(
1156 None,
1157 idkey,
1158 userid,
1159 mydate,
1160 vote,
1161 None,
1162 )
1163 )
1164 if do_commit:
1165 self.commit()
1166 self.update_user_score(userid)
1167 return True
1168
1170 self.check_connection()
1171 idkey = self.handle_pkgkey(pkgkey)
1172 self.execute_query('SELECT `idvote` FROM entropy_votes WHERE `idkey` = %s AND `userid` = %s', (idkey,userid,))
1173 data = self.fetchone()
1174 if data:
1175 return True
1176 return False
1177
1178
1179 - def do_downloads(self, pkgkeys, ip_addr = None, do_commit = False):
1180 self.check_connection()
1181 mydate = self.get_date()
1182 iddownloads = set()
1183 for pkgkey in pkgkeys:
1184 iddownload = self.get_iddownload(pkgkey, mydate)
1185 if iddownload == -1:
1186 iddownload = self.insert_download(pkgkey, mydate, count = 1)
1187 else:
1188 self.update_download(iddownload)
1189 if (iddownload > 0) and isinstance(ip_addr,basestring):
1190 iddownloads.add(iddownload)
1191
1192 if iddownloads:
1193 self.store_download_data(iddownloads, ip_addr)
1194 if do_commit:
1195 self.commit()
1196 return True
1197
1198 - def do_download_stats(self, branch, release_string, hw_hash, pkgkeys,
1199 ip_addr, do_commit = False):
1200
1201 self.check_connection()
1202 branch_id = self.get_entropy_branches_id(branch)
1203 if branch_id == -1:
1204 branch_id = self.insert_entropy_branch(branch)
1205
1206 rel_strings_id = self.get_entropy_release_strings_id(release_string)
1207 if rel_strings_id == -1:
1208 rel_strings_id = self.insert_entropy_release_string(release_string)
1209
1210 self.do_downloads(pkgkeys, ip_addr = ip_addr)
1211
1212 entropy_distribution_usage_id = self.is_user_ip_available_in_entropy_distribution_usage(ip_addr)
1213
1214 hits = 1
1215 if self.STATS_MAP['installer'] in pkgkeys:
1216 hits = 0
1217 if entropy_distribution_usage_id == -1:
1218 entropy_ip_locations_id = self.handle_entropy_ip_locations_id(ip_addr)
1219 self.execute_query('INSERT INTO entropy_distribution_usage VALUES (%s,%s,%s,%s,%s,%s,%s,%s)',(
1220 None,
1221 branch_id,
1222 rel_strings_id,
1223 None,
1224 ip_addr,
1225 entropy_ip_locations_id,
1226 self.get_datetime(),
1227 hits,
1228 )
1229 )
1230 entropy_distribution_usage_id = self.lastrowid()
1231 else:
1232 self.execute_query("""
1233 UPDATE entropy_distribution_usage SET `entropy_branches_id` = %s,
1234 `entropy_release_strings_id` = %s,
1235 `hits` = `hits`+%s
1236 WHERE `entropy_distribution_usage_id` = %s
1237 """,(
1238 branch_id,
1239 rel_strings_id,
1240 hits,
1241 entropy_distribution_usage_id,
1242 )
1243 )
1244
1245
1246 if hw_hash and not \
1247 self.is_entropy_hardware_usage_stats_available(entropy_distribution_usage_id):
1248
1249 self.do_entropy_hardware_usage_stats(entropy_distribution_usage_id,
1250 hw_hash)
1251
1252 if do_commit: self.commit()
1253 return True
1254
1256
1257 self.execute_query('INSERT INTO entropy_hardware_usage VALUES (%s,%s,%s)', (
1258 None,
1259 entropy_distribution_usage_id,
1260 hw_hash,
1261 )
1262 )
1263
1265 self.check_connection()
1266 self.execute_query('SELECT entropy_hardware_usage_id FROM entropy_hardware_usage WHERE `entropy_distribution_usage_id` = %s',(entropy_distribution_usage_id,))
1267 data = self.fetchone()
1268 if data:
1269 return True
1270 return False
1271
1273 self.check_connection()
1274 self.execute_query('SELECT entropy_distribution_usage_id FROM entropy_distribution_usage WHERE `ip_address` = %s',(ip_address,))
1275 data = self.fetchone() or {}
1276 myid = data.get('entropy_distribution_usage_id')
1277 if myid is None:
1278 return -1
1279 return myid
1280
1281 - def insert_document(self, pkgkey, userid, username, text, title,
1282 description, keywords, doc_type = None, do_commit = False):
1283 self.check_connection()
1284 idkey = self.handle_pkgkey(pkgkey)
1285 if doc_type == None: doc_type = self.DOC_TYPES['bbcode_doc']
1286 iddoc = self.insert_generic_doc(idkey, userid, username, doc_type,
1287 text, title, description, keywords)
1288 if isinstance(iddoc, basestring):
1289 return False, iddoc
1290 if do_commit:
1291 self.commit()
1292 return True, iddoc
1293
1294 - def edit_document(self, iddoc, new_document, new_title, new_keywords, do_commit = False):
1313
1326
1328
1329 if not os.access(filepath,os.R_OK):
1330 return False,None
1331
1332 args = [self.VIRUS_CHECK_EXEC]
1333 args += self.VIRUS_CHECK_ARGS
1334 args += [filepath]
1335 f = open("/dev/null","w")
1336 p = subprocess.Popen(args, stdout = f, stderr = f)
1337 rc = p.wait()
1338 f.close()
1339 if rc == 1:
1340 return True, None
1341 return False, None
1342
1343 - def insert_generic_file(self, pkgkey, userid, username, file_path,
1344 file_name, doc_type, title, description, keywords):
1345 self.check_connection()
1346 file_path = os.path.realpath(file_path)
1347
1348
1349 virus_found, virus_type = self.scan_for_viruses(file_path)
1350 if virus_found:
1351 os.remove(file_path)
1352 return False, None
1353
1354
1355 flood_risk = self.insert_flood_control_check(userid)
1356 if flood_risk: return False, 'flooding detected'
1357
1358
1359 if doc_type == self.DOC_TYPES['image']:
1360 valid = False
1361 if os.path.isfile(file_path) and os.access(file_path,os.R_OK):
1362 valid = self.entropyTools.is_supported_image_file(file_path)
1363 if not valid:
1364 return False, 'not a valid image'
1365
1366 dest_path = os.path.join(self.STORE_PATH,file_name)
1367
1368
1369 dest_dir = os.path.dirname(dest_path)
1370 if not os.path.isdir(dest_dir):
1371 try:
1372 os.makedirs(dest_dir)
1373 except OSError, e:
1374 raise PermissionDenied('PermissionDenied: %s' % (e,))
1375 if etpConst['entropygid'] != None:
1376 const_setup_perms(dest_dir,etpConst['entropygid'])
1377
1378 orig_dest_path = dest_path
1379 dcount = 0
1380 while os.path.isfile(dest_path):
1381 dcount += 1
1382 dest_path_name = "%s_%s" % (dcount,os.path.basename(orig_dest_path),)
1383 dest_path = os.path.join(os.path.dirname(orig_dest_path),dest_path_name)
1384
1385 if os.path.dirname(file_path) != dest_dir:
1386 try:
1387 os.rename(file_path, dest_path)
1388 except OSError:
1389
1390 shutil.move(file_path, dest_path)
1391 if etpConst['entropygid'] != None:
1392 try:
1393 const_setup_file(dest_path, etpConst['entropygid'], 0664)
1394 except OSError:
1395 pass
1396
1397 try:
1398 const_set_chmod(dest_path,0664)
1399 except OSError:
1400 pass
1401
1402 title = title[:self.entropy_docs_title_len]
1403 description = description[:self.entropy_docs_description_len]
1404
1405
1406 idkey = self.handle_pkgkey(pkgkey)
1407 self.execute_query('INSERT INTO entropy_docs VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s)',(
1408 None,
1409 idkey,
1410 userid,
1411 username,
1412 doc_type,
1413 file_name,
1414 title,
1415 description,
1416 None,
1417 )
1418 )
1419 iddoc = self.lastrowid()
1420 self.insert_keywords(iddoc, keywords)
1421 store_url = os.path.basename(dest_path)
1422 if self.store_url:
1423 store_url = os.path.join(self.store_url,store_url)
1424 self.update_user_score(userid)
1425 return True, (iddoc, store_url)
1426
1427 - def insert_image(self, pkgkey, userid, username, image_path, file_name,
1428 title, description, keywords):
1429 return self.insert_generic_file(pkgkey, userid, username, image_path,
1430 file_name, self.DOC_TYPES['image'], title, description, keywords)
1431
1432 - def insert_file(self, pkgkey, userid, username, file_path, file_name, title,
1433 description, keywords):
1434 return self.insert_generic_file(pkgkey, userid, username, file_path,
1435 file_name, self.DOC_TYPES['generic_file'], title, description,
1436 keywords)
1437
1440
1443
1445 self.check_connection()
1446
1447 userid = self.get_iddoc_userid(iddoc)
1448 self.execute_query('SELECT `ddata` FROM entropy_docs WHERE `iddoc` = %s AND `iddoctype` = %s',(
1449 iddoc,
1450 doc_type,
1451 )
1452 )
1453 data = self.fetchone() or {}
1454 mypath = data.get('ddata')
1455 if not isinstance(mypath, basestring) and (mypath is not None):
1456 mypath = mypath.tostring()
1457 if mypath is not None:
1458 mypath = os.path.join(self.STORE_PATH,mypath)
1459 if os.path.isfile(mypath) and os.access(mypath,os.W_OK):
1460 os.remove(mypath)
1461
1462 self.remove_keywords(iddoc)
1463 self.execute_query('DELETE FROM entropy_docs WHERE `iddoc` = %s AND `iddoctype` = %s',(
1464 iddoc,
1465 doc_type,
1466 )
1467 )
1468 if userid:
1469 self.update_user_score(userid)
1470 return True, (iddoc, None)
1471
1472 - def insert_youtube_video(self, pkgkey, userid, username, video_path, file_name, title, description, keywords):
1473 self.check_connection()
1474 if not self.gdata:
1475 return False, None
1476
1477 idkey = self.handle_pkgkey(pkgkey)
1478 video_path = os.path.realpath(video_path)
1479 if not (os.access(video_path,os.R_OK) and os.path.isfile(video_path)):
1480 return False
1481 virus_found, virus_type = self.scan_for_viruses(video_path)
1482 if virus_found:
1483 os.remove(video_path)
1484 return False, None
1485
1486 new_video_path = video_path
1487 if isinstance(file_name,basestring):
1488
1489 new_video_path = os.path.join(os.path.dirname(video_path),os.path.basename(file_name))
1490 scount = 0
1491 while os.path.lexists(new_video_path):
1492 scount += 1
1493 bpath = "%s.%s" % (unicode(scount),os.path.basename(file_name),)
1494 new_video_path = os.path.join(os.path.dirname(video_path),bpath)
1495 shutil.move(video_path,new_video_path)
1496
1497 yt_service = self.get_youtube_service()
1498 if yt_service == None:
1499 return False, None
1500
1501 mykeywords = ', '.join([x.strip().strip(',') for x in \
1502 keywords.split() + ["sabayon"] if (x.strip() and x.strip(",") and \
1503 (len(x.strip()) > 4))])
1504 gd_keywords = self.gdata.media.Keywords(text = mykeywords)
1505
1506 mydescription = "%s: %s" % (pkgkey,description,)
1507 mytitle = "%s: %s" % (self.system_name,title,)
1508 my_media_group = self.gdata.media.Group(
1509 title = self.gdata.media.Title(text = mytitle),
1510 description = self.gdata.media.Description(
1511 description_type = 'plain',
1512 text = mydescription
1513 ),
1514 keywords = gd_keywords,
1515 category = self.gdata.media.Category(
1516 text = 'Tech',
1517 scheme = 'http://gdata.youtube.com/schemas/2007/categories.cat',
1518 label = 'Tech'
1519 ),
1520 player = None
1521 )
1522 video_entry = self.gdata.youtube.YouTubeVideoEntry(media = my_media_group)
1523 new_entry = yt_service.InsertVideoEntry(video_entry, new_video_path)
1524 if not isinstance(new_entry, self.gdata.youtube.YouTubeVideoEntry):
1525 return False, None
1526 video_url = new_entry.GetSwfUrl()
1527 video_id = os.path.basename(video_url)
1528
1529 iddoc = self.insert_generic_doc(idkey, userid, username,
1530 self.DOC_TYPES['youtube_video'], video_id, title, description,
1531 keywords)
1532 if isinstance(iddoc,basestring):
1533 return False, (iddoc, None,)
1534 return True, (iddoc, video_id,)
1535
1555
1556 self.execute_query('SELECT `ddata` FROM entropy_docs WHERE `iddoc` = %s AND `iddoctype` = %s',(
1557 iddoc,
1558 self.DOC_TYPES['youtube_video'],
1559 )
1560 )
1561 data = self.fetchone()
1562 if data is None:
1563 do_remove()
1564 return False, None
1565 elif not data.has_key('ddata'):
1566 do_remove()
1567 return False, None
1568
1569 video_id = data.get('ddata')
1570 try:
1571 video_entry = yt_service.GetYouTubeVideoEntry(video_id = video_id)
1572 deleted = yt_service.DeleteVideoEntry(video_entry)
1573 except:
1574 deleted = True
1575
1576 if deleted:
1577 do_remove()
1578 if userid: self.update_user_score(userid)
1579 return deleted, (iddoc, video_id,)
1580
1582 self.check_connection()
1583 if not self.gdata:
1584 return None
1585 keywords = ['google_email', 'google_password']
1586 for keyword in keywords:
1587 if not self.connection_data.has_key(keyword):
1588 return None
1589
1590 srv = self.YouTubeService.YouTubeService()
1591 srv.email = self.connection_data['google_email']
1592 srv.password = self.connection_data['google_password']
1593 if self.connection_data.has_key('google_developer_key'):
1594 srv.developer_key = self.connection_data['google_developer_key']
1595 if self.connection_data.has_key('google_client_id'):
1596 srv.client_id = self.connection_data['google_client_id']
1597 srv.source = 'Entropy'
1598 srv.ProgrammaticLogin()
1599 return srv
1600
1602
1603 import socket
1604 import entropy.dump as dumpTools
1605 import entropy.tools as entropyTools
1606 import zlib
1607 import select
1608 - def __init__(self, OutputInterface, ClientCommandsClass, quiet = False, show_progress = True, output_header = '', ssl = False, socket_timeout = 25):
1609
1610
1611 if not hasattr(OutputInterface,'updateProgress'):
1612 mytxt = _("OutputInterface does not have an updateProgress method")
1613 raise IncorrectParameter("IncorrectParameter: %s, (! %s !)" % (OutputInterface,mytxt,))
1614 elif not callable(OutputInterface.updateProgress):
1615 mytxt = _("OutputInterface does not have an updateProgress method")
1616 raise IncorrectParameter("IncorrectParameter: %s, (! %s !)" % (OutputInterface,mytxt,))
1617
1618 from entropy.client.services.ugc.commands import Base
1619 if not issubclass(ClientCommandsClass, (Base,)):
1620 mytxt = _("A valid entropy.client.services.ugc.commands.Base interface is needed")
1621 raise IncorrectParameter("IncorrectParameter: %s, (! %s !)" % (ClientCommandsClass,mytxt,))
1622
1623 self.ssl_mod = None
1624 self.setup_ssl(ssl)
1625
1626 self.answers = etpConst['socket_service']['answers']
1627 self.Output = OutputInterface
1628 self.sock_conn = None
1629 self.real_sock_conn = None
1630 self.hostname = None
1631 self.hostport = None
1632 self.buffered_data = ''
1633 self.buffer_length = None
1634 self.quiet = quiet
1635 self.show_progress = show_progress
1636 self.output_header = output_header
1637 self.CmdInterface = ClientCommandsClass(self.Output, self)
1638 self.CmdInterface.output_header = self.output_header
1639 self.socket_timeout = socket_timeout
1640 self.socket.setdefaulttimeout(self.socket_timeout)
1641
1642
1644
1645 self.SSL = {}
1646 self.SSL_exceptions = {
1647 'WantReadError': None,
1648 'WantWriteError': None,
1649 'WantX509LookupError': None,
1650 'ZeroReturnError': None,
1651 'Error': None,
1652 'SysCallError': None
1653 }
1654 self.ssl = ssl
1655 self.pyopenssl = True
1656 self.context = None
1657
1658 '''
1659 self.server_cert = server_cert
1660 self.server_ca_cert = server_ca_cert
1661 self.ssl_pkey = None
1662 self.ssl_cert = None
1663 self.ssl_CN = 'Entropy Repository Service Client'
1664 self.ssl_digest = 'md5'
1665 self.ssl_serial = 1
1666 self.ssl_not_before = 0
1667 self.ssl_not_after = 60*60*24*1 # 1 day
1668 '''
1669
1670 if self.ssl:
1671
1672 try:
1673 from OpenSSL import SSL, crypto
1674 except ImportError:
1675 self.pyopenssl = False
1676
1677
1678 try:
1679 import ssl as ssl_mod
1680 self.ssl_mod = ssl_mod
1681 except ImportError:
1682 pass
1683
1684 '''
1685 if not (self.server_cert and self.server_ca_cert):
1686 raise SSLError('SSLError: %s: %s' % (_("Specified SSL server certificate not available"),)
1687 if not (os.path.isfile(self.server_cert) and \
1688 os.access(self.server_cert,os.R_OK) and \
1689 os.path.isfile(self.server_ca_cert) and \
1690 os.access(self.server_ca_cert,os.R_OK)) and self.pyopenssl:
1691 raise SSLError('SSLError: %s: %s' % (_("Specified SSL server certificate not available"),self.server_cert,))
1692 '''
1693
1694 if self.pyopenssl:
1695
1696 self.SSL_exceptions['WantReadError'] = SSL.WantReadError
1697 self.SSL_exceptions['WantWriteError'] = SSL.WantWriteError
1698 self.SSL_exceptions['WantX509LookupError'] = SSL.WantX509LookupError
1699 self.SSL_exceptions['ZeroReturnError'] = SSL.ZeroReturnError
1700 self.SSL_exceptions['Error'] = SSL.Error
1701 self.SSL_exceptions['SysCallError'] = SSL.SysCallError
1702 self.SSL['m'] = SSL
1703 self.SSL['crypto'] = crypto
1704
1705
1706 self.context = self.SSL['m'].Context(self.SSL['m'].SSLv23_METHOD)
1707
1708
1709
1710 '''
1711 self.ssl_pkey = self.create_ssl_key_pair(self.SSL['crypto'].TYPE_RSA, 1024)
1712 self.context.use_privatekey(self.ssl_pkey)
1713 self.context.use_certificate_file(self.server_cert)
1714 self.context.load_verify_locations(self.server_ca_cert)
1715 self.context.load_client_ca(self.server_cert)
1716 self.ssl_pkey = self.create_ssl_key_pair(self.SSL['crypto'].TYPE_RSA, 1024)
1717 self.ssl_cert = self.create_ssl_certificate(self.ssl_pkey)
1718 self.context.use_privatekey(self.ssl_pkey)
1719 self.context.use_certificate(self.ssl_cert)
1720 self.context.load_client_ca(self.server_cert)
1721 '''
1722
1723 else:
1724 self.ssl = False
1725 self.pyopenssl = False
1726
1727
1729 if not self.pyopenssl:
1730 raise SSLError('SSLError: %s' % (_("OpenSSL Python module not available, you need dev-python/pyopenssl"),))
1731
1732 '''
1733 # this function should do the authentication checking to see that
1734 # the client is who they say they are.
1735 def verify_ssl_cb(self, conn, cert, errnum, depth, ok):
1736 self.check_pyopenssl()
1737 #print 'Got certificate: %s' % cert.get_subject()
1738 #print repr(ok),repr(cert),repr(errnum),repr(depth)
1739 return ok
1740
1741
1742 def create_ssl_key_pair(self, keytype, bits):
1743 if not self.pyopenssl:
1744 raise SSLError('SSLError: %s' % (_("OpenSSL Python module not available, you need dev-python/pyopenssl"),))
1745 pkey = self.SSL['crypto'].PKey()
1746 pkey.generate_key(keytype, bits)
1747 return pkey
1748
1749 def create_ssl_certificate(self, pkey):
1750 self.check_pyopenssl()
1751 myreq = self.create_ssl_certificate_request(pkey, CN = self.ssl_CN)
1752 cert = self.SSL['crypto'].X509()
1753 cert.set_serial_number(self.ssl_serial)
1754 cert.gmtime_adj_notBefore(self.ssl_not_before)
1755 cert.gmtime_adj_notAfter(self.ssl_not_after)
1756 cert.set_issuer(myreq.get_subject())
1757 cert.set_subject(myreq.get_subject())
1758 cert.set_pubkey(myreq.get_pubkey())
1759 cert.sign(pkey, self.ssl_digest)
1760 return cert
1761
1762 def create_ssl_certificate_request(self, pkey, **name):
1763 self.check_pyopenssl()
1764 req = self.SSL['crypto'].X509Req()
1765 subj = req.get_subject()
1766 for (key,value) in name.items():
1767 setattr(subj, key, value)
1768 req.set_pubkey(pkey)
1769 req.sign(pkey, self.ssl_digest)
1770
1771 return req
1772 '''
1773
1775
1776 if gzipped:
1777 data = self.zlib.decompress(data)
1778 obj = self.dumpTools.unserialize_string(data)
1779
1780 return obj
1781
1783 return str(len(data))+self.answers['eos']+data
1784
1786 self.check_socket_connection()
1787 if hasattr(self.sock_conn,'settimeout'):
1788 self.sock_conn.settimeout(self.socket_timeout)
1789 data = self.append_eos(data)
1790 try:
1791
1792 if self.ssl and not self.pyopenssl:
1793 try:
1794 self.sock_conn.write(data)
1795 except UnicodeEncodeError:
1796 self.sock_conn.write(data.encode('utf-8'))
1797 else:
1798 encode_done = False
1799 mydata = data[:]
1800 while 1:
1801 try:
1802 sent = self.sock_conn.send(mydata)
1803 if sent == len(mydata):
1804 break
1805 mydata = mydata[sent:]
1806 except (self.SSL_exceptions['WantWriteError'],self.SSL_exceptions['WantReadError'],):
1807 time.sleep(0.2)
1808 continue
1809 except UnicodeEncodeError, e:
1810 if encode_done:
1811 raise
1812 mydata = mydata.encode('utf-8')
1813 encode_done = True
1814 continue
1815
1816 except self.SSL_exceptions['Error'], e:
1817 self.disconnect()
1818 raise SSLError('SSLError: %s' % (e,))
1819 except self.socket.sslerror, e:
1820 self.disconnect()
1821 raise SSLError('SSL Socket error: %s' % (e,))
1822 except:
1823 self.disconnect()
1824 raise
1825
1827 self.check_socket_connection()
1828 try:
1829 self.transmit("%s end" % (session_id,))
1830
1831 data = self.receive()
1832 except self.socket.error, e:
1833 if etpUi['debug']:
1834 self.entropyTools.print_traceback()
1835 import pdb
1836 pdb.set_trace()
1837 if e[0] == 32:
1838 return None
1839 raise
1840 except SSLError:
1841 raise
1842 return data
1843
1850
1852 self.check_socket_connection()
1853 self.socket.setdefaulttimeout(self.socket_timeout)
1854 self.transmit('alive %s' % (session,))
1855 data = self.receive()
1856 if data == self.answers['ok']:
1857 return True
1858 return False
1859
1861
1862 self.check_socket_connection()
1863 if hasattr(self.sock_conn,'settimeout'):
1864 self.sock_conn.settimeout(self.socket_timeout)
1865 self.ssl_prepending = True
1866
1867 def do_receive():
1868 data = ''
1869 if self.ssl and not self.pyopenssl:
1870 data = self.sock_conn.read(1024)
1871 elif self.ssl:
1872 if self.ssl_prepending:
1873 data = self.sock_conn.recv(1024)
1874 self.ssl_prepending = False
1875 while self.sock_conn.pending():
1876 data += self.sock_conn.recv(1024)
1877 else:
1878 data = self.sock_conn.recv(1024)
1879 return data
1880
1881 myeos = self.answers['eos']
1882 ssl_error_loop_count = 0
1883 while 1:
1884
1885 try:
1886
1887 data = do_receive()
1888 if self.buffer_length == None:
1889 self.buffered_data = ''
1890 if (data == '') or (data == self.answers['cl']):
1891
1892
1893 if not self.quiet:
1894 mytxt = _("command not supported. receive aborted")
1895 self.Output.updateProgress(
1896 "[%s:%s] %s" % (
1897 brown(self.hostname),
1898 bold(str(self.hostport)),
1899 blue(mytxt),
1900 ),
1901 importance = 1,
1902 type = "warning",
1903 header = self.output_header
1904 )
1905 return None
1906 elif len(data) < len(myeos):
1907 if not self.quiet:
1908 mytxt = _("malformed EOS. receive aborted")
1909 self.Output.updateProgress(
1910 "[%s:%s] %s" % (
1911 brown(self.hostname),
1912 bold(str(self.hostport)),
1913 blue(mytxt),
1914 ),
1915 importance = 1,
1916 type = "warning",
1917 header = self.output_header
1918 )
1919 if etpUi['debug']:
1920 self.entropyTools.print_traceback()
1921 import pdb
1922 pdb.set_trace()
1923 return None
1924 mystrlen = data.split(myeos)[0]
1925 self.buffer_length = int(mystrlen)
1926 data = data[len(mystrlen)+1:]
1927 self.buffer_length -= len(data)
1928 self.buffered_data = data
1929 else:
1930 self.buffer_length -= len(data)
1931 self.buffered_data += data
1932
1933 while self.buffer_length > 0:
1934 x = do_receive()
1935 if self.ssl and self.pyopenssl and not x:
1936 self.ssl_prepending = True
1937 self.buffer_length -= len(x)
1938 self.buffered_data += x
1939 self.buffer_length = None
1940 break
1941
1942 except ValueError, e:
1943 if not self.quiet:
1944 mytxt = _("malformed data. receive aborted")
1945 self.Output.updateProgress(
1946 "[%s:%s] %s: %s" % (
1947 brown(self.hostname),
1948 bold(str(self.hostport)),
1949 blue(mytxt),
1950 e,
1951 ),
1952 importance = 1,
1953 type = "warning",
1954 header = self.output_header
1955 )
1956 return None
1957 except self.socket.timeout, e:
1958 if not self.quiet:
1959 mytxt = _("connection timed out while receiving data")
1960 self.Output.updateProgress(
1961 "[%s:%s] %s: %s" % (
1962 brown(self.hostname),
1963 bold(str(self.hostport)),
1964 blue(mytxt),
1965 e,
1966 ),
1967 importance = 1,
1968 type = "warning",
1969 header = self.output_header
1970 )
1971 return None
1972 except self.socket.error, e:
1973 if not self.quiet:
1974 mytxt = _("connection error while receiving data")
1975 self.Output.updateProgress(
1976 "[%s:%s] %s: %s" % (
1977 brown(self.hostname),
1978 bold(str(self.hostport)),
1979 blue(mytxt),
1980 e,
1981 ),
1982 importance = 1,
1983 type = "warning",
1984 header = self.output_header
1985 )
1986 return None
1987 except (self.SSL_exceptions['WantReadError'],self.SSL_exceptions['WantX509LookupError'],), e:
1988 ssl_error_loop_count += 1
1989 if ssl_error_loop_count > 3000000:
1990 if not self.quiet:
1991 mytxt = _("too many WantReadError error while receiving data")
1992 self.Output.updateProgress(
1993 "[%s:%s] %s: %s" % (
1994 brown(self.hostname),
1995 bold(str(self.hostport)),
1996 blue(mytxt),
1997 e,
1998 ),
1999 importance = 1,
2000 type = "warning",
2001 header = self.output_header
2002 )
2003 return None
2004 continue
2005 except self.SSL_exceptions['ZeroReturnError']:
2006 break
2007 except self.SSL_exceptions['SysCallError'], e:
2008 if not self.quiet:
2009 mytxt = _("syscall error while receiving data")
2010 self.Output.updateProgress(
2011 "[%s:%s] %s: %s" % (
2012 brown(self.hostname),
2013 bold(str(self.hostport)),
2014 blue(mytxt),
2015 e,
2016 ),
2017 importance = 1,
2018 type = "warning",
2019 header = self.output_header
2020 )
2021 return None
2022
2023 return self.buffered_data
2024
2026 if not self.quiet:
2027 mytxt = _("Reconnecting to socket")
2028 self.Output.updateProgress(
2029 "[%s:%s] %s" % (
2030 brown(unicode(self.hostname)),
2031 bold(unicode(self.hostport)),
2032 blue(mytxt),
2033 ),
2034 importance = 1,
2035 type = "info",
2036 header = self.output_header
2037 )
2038 self.connect(self.hostname,self.hostport)
2039
2041 if not self.sock_conn:
2042 raise ConnectionError("ConnectionError: %s" % (_("Not connected to host"),))
2043
2045
2046 if self.ssl:
2047 self.real_sock_conn = self.socket.socket(self.socket.AF_INET, self.socket.SOCK_STREAM)
2048 if hasattr(self.real_sock_conn,'settimeout'):
2049 self.real_sock_conn.settimeout(self.socket_timeout)
2050 if self.pyopenssl:
2051 self.sock_conn = self.SSL['m'].Connection(self.context, self.real_sock_conn)
2052 else:
2053 self.sock_conn = self.real_sock_conn
2054 else:
2055 self.sock_conn = self.socket.socket(self.socket.AF_INET, self.socket.SOCK_STREAM)
2056 if hasattr(self.sock_conn,'settimeout'):
2057 self.sock_conn.settimeout(self.socket_timeout)
2058 self.real_sock_conn = self.sock_conn
2059
2060 self.hostname = host
2061 self.hostport = port
2062
2063 try:
2064 self.sock_conn.connect((self.hostname, self.hostport))
2065 if self.ssl and not self.pyopenssl:
2066 if self.ssl_mod != None:
2067 self.sock_conn = self.ssl_mod.wrap_socket(self.real_sock_conn)
2068 else:
2069 self.sock_conn = self.socket.ssl(self.real_sock_conn)
2070
2071 if not self.quiet:
2072 mytxt = _("Warning: you are using an emergency SSL interface, SSL certificate can't be verified. Please install dev-python/pyopenssl")
2073 self.Output.updateProgress(
2074 "[%s:%s] %s" % (
2075 brown(str(self.hostname)),
2076 bold(str(self.hostport)),
2077 blue(mytxt),
2078 ),
2079 importance = 1,
2080 type = "warning",
2081 header = self.output_header
2082 )
2083 mytxt = _("Service issuer")
2084 self.Output.updateProgress(
2085 "[%s:%s] %s: %s" % (
2086 brown(str(self.hostname)),
2087 bold(str(self.hostport)),
2088 blue(mytxt),
2089 self.sock_conn.issuer()
2090 ),
2091 importance = 1,
2092 type = "warning",
2093 header = self.output_header
2094 )
2095 except self.socket.error, e:
2096 if e[0] == 111:
2097 mytxt = "%s: %s, %s: %s" % (_("Cannot connect to"),host,_("on port"),port,)
2098 raise ConnectionError("ConnectionError: %s" % (mytxt,))
2099 else:
2100 raise
2101
2102 if not self.quiet:
2103 mytxt = _("Successfully connected to host")
2104 self.Output.updateProgress(
2105 "[%s:%s] %s" % (
2106 brown(self.hostname),
2107 bold(str(self.hostport)),
2108 blue(mytxt),
2109 ),
2110 importance = 1,
2111 type = "info",
2112 header = self.output_header
2113 )
2114
2116 if not self.real_sock_conn:
2117 return True
2118 if self.ssl and self.pyopenssl:
2119 self.sock_conn.shutdown()
2120 self.sock_conn.close()
2121 elif self.ssl and not self.pyopenssl:
2122 try:
2123 self.real_sock_conn.shutdown(self.socket.SHUT_RDWR)
2124 except self.socket.error:
2125 pass
2126 del self.sock_conn
2127 self.sock_conn = None
2128 try:
2129 self.real_sock_conn.close()
2130 except self.socket.error:
2131 pass
2132 if not self.quiet:
2133 mytxt = _("Successfully disconnected from host")
2134 self.Output.updateProgress(
2135 "[%s:%s] %s" % (
2136 brown(self.hostname),
2137 bold(str(self.hostport)),
2138 blue(mytxt),
2139 ),
2140 importance = 1,
2141 type = "info",
2142 header = self.output_header
2143 )
2144 self.real_sock_conn = None
2145
2146
2147
2148