Completed
Push — master ( a34a93...a21e2b )
by Sepand
01:00
created

list_randomize()   A

Complexity

Conditions 2

Size

Total Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 2
c 1
b 0
f 1
dl 0
loc 15
rs 9.4285
1
import shutil  # Library For Work With File In High Level Like Copy
2
import webbrowser
3
from params import *
4
import socket
5
import requests
6
import re
7
import time
8
import sys
9
import urllib.request
10
import platform
11
import random
12
import datetime
13
from functools import reduce
14
import doctest
15
meta_input = ""
16
def list_randomize(input_list):
17
    '''
18
    :param input_list: raw_input list
19
    :type input_list:list
20
    :return: randomized list
21
    >>> random.seed(1)
22
    >>> list_randomize([1,2,3,5,6])
23
    [2, 1, 5, 3, 6]
24
    '''
25
    response=[]
26
    input_list_copy=input_list
27
    iteration_number=len(input_list_copy)
28
    for i in range(iteration_number):
29
        response.append(input_list_copy.pop(random.randint(0,len(input_list_copy)-1)))
30
    return response
31
def email_at(text,USE_RE=False,replace_char=" at "):
32
    '''
33
    :param text: input text of pages
34
    :param USE_RE: flag for using regular expression (default False)
35
    :param replace_char: replace char for @
36
    :type text:str
37
    :type USE_RE:bool
38
    :type replace_char:str
39
    :return: replaced string
40
    >>> email_at("[email protected]")
41
    'example at yahoo.com'
42
    >>>
43
    '''
44
    if USE_RE==False:
45
        return text.replace("@",replace_char)
46
def show_items(enum_list):
47
    """
48
    show item of enum_list
49
    :param enum_list the list that should be shown
50
    :type enum_list : list
51
    """
52
    for i, item in enumerate(enum_list):
53
        print(str(i + 1) + "-" + item)
54
def print_logo(external=False):
55
    '''
56
    print qpage logo by sequential characters
57
    :param external: flag for choosing internal or external logo
58
    :type external:bool
59
    :return: None
60
    >>> print_logo()
61
      ____    ___
62
     / __ \  / _ \___ ____ ____
63
    / /_/ / / ___/ _ `/ _ `/ -_)
64
    \___\_\/_/   \_,_/\_, /\__/
65
                     /___/
66
    '''
67
    if external==True:
68
        if "logo.txt" in os.listdir(RESOURCE_DIR):
69
            logo_path = os.path.join(RESOURCE_DIR, 'logo.txt')
70
            with open(logo_path, "r") as logo_file:
71
                for line in logo_file:
72
                    print(line.rstrip())
73
        else:
74
            pass
75
    else:
76
        print(LOGO)
77
def convert_bytes(num):
78
    """
79
    convert num to idiomatic byte unit
80
    :param num: the input number.
81
    :type num:int
82
    :return: str
83
    >>> convert_bytes(200)
84
    '200.0 bytes'
85
    >>> convert_bytes(6000)
86
    '5.9 KB'
87
    >>> convert_bytes(80000)
88
    '78.1 KB'
89
    """
90
    for x in ['bytes', 'KB', 'MB', 'GB', 'TB']:
91
        if num < 1024.0:
92
            return "%3.1f %s" % (num, x)
93
        num /= 1024.0
94
def file_size():
95
    """
96
    Print the size of output file
97
    :return: None
98
    >>> file_size() # if there is no output directory
99
    Access Error
100
    >>> file_size() # if there is a valid output directory
101
    Used SPACE --> 78.1 KB
102
    """
103
    try:
104
        list_of_files = os.listdir(OUT_DIR)
105
        response = 0
106
        for file in list_of_files:
107
            file_info = os.stat(os.path.join(OUT_DIR, file))
108
            response += file_info.st_size
109
        print_line(70, "*")
110
        print("Used SPACE --> " + convert_bytes(response))
111
        print_line(70, "*")
112
    except:
113
        print("Access Error!")
114
def download_badge(address):
115
116
    """
117
    Download badge for website
118
    :param address: the address that should get badge
119
    :type address : str
120
    :return: None
121
    """
122
    r = requests.get(address, stream=True)
123
    with open(os.path.join(OUT_DIR, "badge.svg"), 'wb') as f:
124
        shutil.copyfileobj(r.raw, f)
125
def random_badge_color():
126
    """
127
    return a random color for badge
128
    :return: badge color as string
129
    >>> random.seed(1)
130
    >>> random_badge_color()
131
    'yellowgreen'
132
    """
133
    random_index = random.randint(0, len(BADGE_COLOR_LIST) - 1)
134
    return BADGE_COLOR_LIST[random_index]
135
def system_details():
136
    """
137
    Show detail of system that code is runnig on
138
    :return: system details as string (node , processor , platform)
139
    >>> system_details()
140
    'DESKTOP-B16C9BR , Intel64 Family 6 Model 94 Stepping 3, GenuineIntel ,  Windows-10-10.0.10240-SP0'
141
    """
142
    return platform.node() + " , " + platform.processor() + " ,  " + platform.platform()
143
def generation_time(time_1=None):
144
    """
145
    Calculate the generation time
146
    :param time_1: time that passed but not counted in generation time
147
    :type time_1:float
148
    :return :the amount of time that passed  as float
149
    """
150
    if time_1 is None:
151
        return time.perf_counter()
152
    else:
153
        return time.perf_counter() - time_1
154
def find_global_ip():
155
    """
156
    Find the global IP for using in API
157
    :return: return the IP as string
158
    """
159
    try:
160
        response = requests.get(IP_FINDER_API)
161
        return response.text[:-1]
162
    except Exception as e:
163
        error_log(e)
164
        return "0.0.0.0"
165
def create_badge(subject="qpage", status=VERSION, color="blue", random=False):
166
    '''
167
    this function use shields.io template for creating  badges
168
    :param subject: badge subject
169
    :param status: badge status ( in our case version)
170
    :param color: badge color
171
    :param random: randomization flag
172
    :type subject:str
173
    :type status:str
174
    :type color:str
175
    :type random:bool
176
    :return: shields.io badge addresses as string
177
    >>> create_badge()
178
    'https://img.shields.io/badge/qpage-1.9-blue.svg'
179
    >>> random.seed(1)
180
    >>> create_badge(random=True)
181
    'https://img.shields.io/badge/qpage-1.9-yellowgreen.svg'
182
    '''
183
    if random:
184
        color = random_badge_color()
185
    else:
186
        if color not in BADGE_COLOR_LIST:
187
            color = "orange"
188
    badge_adr = ADV_BADGE_STATIC + subject + "-" + status + "-" + color + '.svg'
189
    return badge_adr
190
def is_sample_downloaded():
191
    """
192
    Check the sample site material is downloaded of not
193
    :return : index of materials that downloaded as list
194
    """
195
    download_list = []
196
    if "profile.png" not in os.listdir(IMAGE_DIR):
197
        download_list.append(0)
198
    if "font.TTF" not in os.listdir(FONT_DIR):
199
        download_list.append(1)
200
    if "resume.pdf" not in os.listdir(DOC_DIR) and "resume.txt" not in os.listdir(DOC_DIR):
201
        download_list.extend([2, 3])
202
    if "icon.ico" not in os.listdir(IMAGE_DIR):
203
        download_list.append(4)
204
    return download_list
205
def download_lorem():
206
    """
207
    Download the lorem file
208
    :return: None
209
    """
210
    if internet():
211
        lorem_path = os.path.join(RESOURCE_DIR, 'Latin-Lipsum.txt')
212
        urllib.request.urlretrieve("http://www.qpage.ir/sample/Latin-Lipsum.txt", lorem_path)
213
    else:
214
        print("Error In Download Lorem")
215
def read_lorem(char=100,external=False,randomize=True):
216
    """
217
    find and read lorem
218
    :param char: the amount of char that needed to print
219
    :param external: flag for using external of internal resource for lorem_ipsum
220
    :param randomize: flag for using randomization
221
    :type char:int
222
    :type external:bool
223
    :type randomize:bool
224
    :return : the lorem string
225
    >>> read_lorem(5)
226
    'Lorem ipsum dolor sit amet,'
227
    """
228
    try:
229
        if external==True:
230
            if "Latin-Lipsum.txt" not in os.listdir(RESOURCE_DIR):
231
                download_lorem()
232
            lorem_path = os.path.join(RESOURCE_DIR, 'Latin-Lipsum.txt')
233
            lorem_file = open(lorem_path, "r")
234
            lorem_text = lorem_file.read()
235
            lorem_file.close()
236
            if randomize==True:
237
                return " ".join(list_randomize(lorem_text.split(" ")[:char]))
238
            else:
239
                return " ".join(lorem_text.split(" ")[:char])
240
        else:
241
            if randomize==True:
242
                return " ".join(list_randomize(LOREM_IPSUM.split(" ")[:char]))
243
            else:
244
                return " ".join(LOREM_IPSUM.split(" ")[:char])
245
    except Exception as e:
246
        error_log(str(e))
247
        return None
248
def sample_site_download(item_list):
249
    """
250
    Download sample material for make a fake site
251
    :param item_list: Download items form item_list
252
    :type item_list:list
253
    """
254
    try:
255
        if internet():
256
            for i in item_list:
257
                print("Downloading " + SAMPLE_DICT_MESSAGE[i] + " . . . [" + str(i + 1) + "/5]")
258
                print_line(70)
259
                urllib.request.urlretrieve(list(SAMPLE_DICT_ADDR.values())[i],
260
                                           os.path.join(IMAGE_DIR, list(SAMPLE_DICT_ADDR.keys())[i]))
261
            print("Done! All Material Downloaded")
262
            print_line(70)
263
        else:
264
            print("Error In Internet Connection!")
265
            print_line(70)
266
    except Exception as e:
267
        error_log(e)
268
        print("Error in downloading sample files check your internet conection")
269
        print_line(70)
270
def logger(status=False, perf_time=None):
271
    """
272
    Create the build log of the app
273
    :param status: show status of app.
274
    :param perf_time : show the time passed for generate files
275
    :type status:bool
276
    :type perf_time:float
277
    """
278
    if "log" not in os.listdir():
279
        os.mkdir("log")
280
    file = open(reduce(os.path.join, [os.getcwd(), "log", "build_log.txt"]), "a")
281
    if not status:
282
        file.write("Failed  " + str(datetime.datetime.now()) + "\n")
283
    else:
284
        file.write("Success " + str(datetime.datetime.now()) + "\n")
285
        file.write("Generation Time: " + str(perf_time) + "\n")
286
    file.close()
287
def error_log(msg):
288
    """
289
    Create the errorlog of the app
290
    :param msg: error message
291
    :type msg:str
292
    """
293
    if "log" not in os.listdir():
294
        os.mkdir("log")
295
    file = open(reduce(os.path.join, [os.getcwd(), "log", "error_log.txt"]), "a")
296
    file.write(str(datetime.datetime.now()) + " --> " + str(msg) + "\n")
297
    file.close()
298
def print_line(number, char="-"):
299
    """
300
    Print a Line
301
    :param number: the amount char that in lien
302
    :param char  : the char that used to draw line
303
    :type number :int
304
    :type char : str
305
    >>> print_line(4)
306
    ----
307
    >>> print_line(5,"%")
308
    %%%%%
309
    """
310
    line = ""
311
    i = 0
312
    while (i < number):
313
        line += char
314
        i += 1
315
    print(line)
316
def name_standard(name):
317
    """
318
    return the Standard VERSION of the input word
319
    :param name: the name that should be standard
320
    :type name:str
321
    :return name: the standard form of word as string
322
    >>> name_standard('test')
323
    'Test'
324
    >>> name_standard('TesT')
325
    'Test'
326
    """
327
    reponse_name = name[0].upper() + name[1:].lower()
328
    return reponse_name
329
def address_print():
330
    """
331
    Print the working directory
332
    :return:None
333
    """
334
    print_line(70, "*")
335
    print("Where --> " + SOURCE_DIR)
336
    print_line(70, "*")
337
def create_folder():
338
    """
339
    This Function Create Empty Folder At Begin
340
    :return:folder status as boolean
341
    """
342
    folder_flag = 0
343
    list_of_folders = os.listdir(SOURCE_DIR)
344
    for i in ["doc", "image", "output", "font"]:
345
        if i not in list_of_folders:
346
            os.mkdir(i)
347
            folder_flag += 1
348
            if i == "doc":
349
                file = open(os.path.join(DOC_DIR, "index.txt"), "w")
350
                if read_lorem() is None:
351
                    file.write("This is For First Page . . .")
352
                else:
353
                    file.write(read_lorem())
354
                file.close()
355
    return bool(folder_flag)
356
def page_name_update():
357
    """
358
    This Function Update Page Names
359
    :return: None
360
    """
361
    for i in os.listdir(DOC_DIR):
362
        if i.find(".txt") != -1 and i[:-4].upper() != "INDEX":
363
            ACTUAL_NAME.append(i[:-4])
364
            PAGE_NAME.append(i[:-4])
365
def menu_maker():
366
    """
367
    Top Menu Maker In each html page
368
    :return:site menu as string
369
    """
370
    result = "<center>"
371
    for i, item in enumerate(PAGE_NAME):
372
        if item == "Home":
373
            targets_blank = ""
374
        else:
375
            #targets_blank = 'target="blank"'
376
            targets_blank = ''
377
            # Hyper Link To Each Page In HTML File
378
        result += '\t<a href="' \
379
                  + ACTUAL_NAME[i] + '.html"' + targets_blank + '>' + name_standard(item) + "</a>\n"
380
        result += "&nbsp\n"
381
    result += "</center>"
382
    result = result + "\t\t" + BREAK_LINE  # Add Break line to End Of The Menu
383
    return result  # Return All Of The Menu
384
def menu_writer():  #
385
    """
386
    Write menu_maker output in html and close file after
387
    :return:None
388
    """
389
    message = menu_maker()
390
    PAGE_NAME_length = len(PAGE_NAME)
391
    for i in range(PAGE_NAME_length):
392
        file = open(os.path.join(OUT_DIR, ACTUAL_NAME[i] + ".html"), "a")
393
        file.write(message)
394
        file.close()
395
def print_meta():
396
    """
397
    Add meta to html files
398
    :return static_meta: The meta that created
399
    """
400
    global meta_input
401
    meta_input = input("Please Enter Your Name : ")
402
    static_meta = '<meta name="description" content="Welcome to HOMEPAGE of ' + meta_input + '"/>\n'
403
    static_meta += '<meta property="og:title" content="' + meta_input + '"/>\n'
404
    static_meta += '<meta property="og:site_name" content="' + meta_input + '"/>\n'
405
    static_meta += '<meta property="og:image" content="favicon.ico" />\n'
406
    if len(meta_input) < 4:
407
        warnings.append("[Warning] Your input for name is too short!!")
408
    return static_meta
409
def html_init(name):
410
    """
411
    Create Initial Form Of each Html Page Like Title And HTML  And Body Tag.
412
    :param name: the name of html file.
413
    :type name:str
414
    """
415
416
    html_name = os.path.join(OUT_DIR, name + ".html")
417
    file = open(html_name, "w")
418
    file.write("<html>\n")
419
    file.write("\t<head>\n")
420
    if name == "index":
421
        file.write("\t\t<title>Welcome To My HOMEPAGE</title>\n")
422
    else:
423
        file.write("\t\t<title>" + name_standard(name) + "</title>\n")
424
    file.write('<link rel="stylesheet" href="styles.css" type="text/css"/>\n')
425
    css_link = 'https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css'
426
    file.write('<link rel="stylesheet" href= ' + css_link + ' type="text/style"/>\n')
427
428
    if name == 'index':  # Add meta only for index page
429
        file.write(print_meta())
430
431
    file.write("\t</head>\n")
432
    file.write('\t<body class="body_tag">\n')
433
    file.close()
434
def html_end(name):
435
    """
436
    Create End Of The Html and close file
437
    :param name: The name of html file.
438
    :type name:str
439
    """
440
    html_name = os.path.join(OUT_DIR, name + ".html")
441
    file = open(html_name, "a")
442
    file.write("\n\t</body>\n")
443
    file.write("</html>")
444
    file.close()
445
def close_files():
446
    """
447
    Close all the files.
448
    :return:None
449
    """
450
    for i in files:
451
        if i.closed == False:
452
            i.close()
453
def LSM_translate(line, center):
454
    # TODO : write a document for this function
455
    """
456
    Convert size and style of each line in input plaintext
457
    :param line: the input line.
458
    :param center: flag of putting text in center
459
    :type center:bool
460
    :type line:str
461
    :return : return a list contain text,header_end and header_begin
462
    """
463
    line.strip()
464
    text = line
465
    header_start = '<h4 class="color_tag">'
466
    header_end = "</h4>"
467
    if line.find("[L]") != -1:
468
        header_start = '<h2 class="color_tag">'
469
        header_end = "</h2>"
470
        text = line[3:]
471
    elif line.find("[S]") != -1:
472
        header_start = '<h5 class="color_tag">'
473
        header_end = "</h5>"
474
        text = line[3:]
475
    elif line.find("[M]") != -1:
476
        text = line[3:]
477
    if center:  # Centuries Text If Condition Is True For Manual Centering
478
        header_start = "<center>" + header_start
479
        header_end += "</center>"
480
    if text.find("[center]") != -1:  # Find Center Tag In Each Line
481
        header_start = "<center>" + header_start
482
        header_end += "</center>"
483
        text = text[:text.find("[center]")]
484
    return [text, header_end, header_start]
485
def print_text(text_file, file, center=False, close=False):  # Write Text Part Of Each Page
486
    """
487
    Write the text part of each page
488
    :param text_file: Text that should be written.
489
    :param file     : The file that text will be written inside.
490
    :param center: flag of putting text in center
491
    :param close : flag of closing file after editing
492
    :type close : bool
493
    :type center: bool
494
    :type file:_io.TextIOWrapper
495
    :type text_file:str
496
    :return:None
497
    """
498
    text_code = ""
499
    for line in text_file:
500
        if len(line) == 1:
501
            text_code = SPACE
502
        else:
503
            text_header = LSM_translate(line, center)
504
            text = email_at(text=text_header[0])
505
            header_end = text_header[1]
506
            header_start = text_header[2]
507
            text_code = header_start + text + header_end + "\n"
508
        file.write(text_code)
509
    if close:
510
        file.close()
511
def print_image(file, image_format="jpg", close=False):
512
    """
513
    Write Image Part OF The Page.
514
    :param file: The file that images will be added.
515
    :param close : flag of closing file after editing
516
    :param image_format: the format of image
517
    :type close : bool
518
    :type image_format:str
519
    :type file:_io.TextIOWrapper
520
    :return:None
521
    """
522
    for i, item in enumerate(SIZE_BOX):
523
        print(i, "-", item)
524
    image_size = int(input("Please Enter Profile Image Size : "))  # Choose Profile Image Size
525
    image_size_string = SIZE_BOX[2]  # Getting Html String From SIZE_BOX list default mode (Medium)
526
    if 0 <= image_size < len(SIZE_BOX):
527
        image_size_string = SIZE_BOX[image_size]
528
    image_code = '<center><img src="image.' + image_format + '"' + ', width=' + image_size_string + ' alt="profile image"></img></center>\n'
529
    file.write(image_code)
530
    if close:
531
        file.close()
532
def print_download(file, name, link, center=False, close=False):
533
    """
534
    Create Download Link in page
535
    :param file: The file that contain html of page.
536
    :param name: The name of the link
537
    :param link: The place that name is Linked
538
    :param center: put the text in center
539
    :param close : close file after done editing
540
    :type center: bool
541
    :type close : bool
542
    :type link:str
543
    :type name:str
544
    :type file:_io.TextIOWrapper
545
    :return:None
546
    """
547
    link_code = "<a href=" + '"' + link + '"' + TARGET_BLANK + '>' + name + "</a>"
548
    if center:
549
        link_code = "<center>" + link_code + "</center>"
550
    file.write(link_code + "\n")
551
    file.write(BREAK_LINE)
552
    if close:
553
        file.close()
554
def print_adv(file, close=True):
555
    """
556
    Print the advertisement (qpage footer)
557
    :param file  : The file that should adv to it.
558
    :param close : Close file after add
559
    :type file:_io.TextIOWrapper
560
    :type close:bool
561
    :return: None
562
    """
563
    file.write(BREAK_LINE)
564
    file.write(
565
        '<center>' + "<p>" + "Generated " + today_time + " By" + "</p>" + '<a href=' + '"' + HOMEPAGE + '"' + TARGET_BLANK + '>' + '<img src="' + create_badge(
566
            random=True) + '"alt="Qpage">' + '</a> </center>')
567
    if close:
568
        file.close()
569
def build_index(file):
570
    """
571
    Find and build index page
572
    :param file: The index file.
573
    :type file:_io.TextIOWrapper
574
    :return:None
575
    """
576
    image_name = ""
577
    img_format = "jpg"
578
    file_of_images = os.listdir(IMAGE_DIR)
579
    for i in file_of_images:
580
        for form in IMFORMAT_BOX:
581
            if i.find("." + form) != -1:
582
                image_name = os.path.join(IMAGE_DIR, i)
583
                img_format = form
584
                global IMAGE_COUNTER
585
                IMAGE_COUNTER = 1
586
                break
587
    shutil.copyfile(image_name, os.path.join(OUT_DIR, "image." + img_format))
588
    print_image(file, img_format)
589
def build_resume(file):
590
    """
591
    Find and build resume page.
592
    :param file: The resume file.
593
    :type file:_io.TextIOWrapper
594
    :return:None
595
    """
596
    resume_name = ""
597
    file_of_docs = os.listdir(DOC_DIR)
598
    for i in file_of_docs:
599
        if i.find(".pdf") != -1:
600
            resume_name = os.path.join(DOC_DIR, i)
601
            global PDF_COUNTER
602
            PDF_COUNTER = 1
603
            break
604
    shutil.copyfile(resume_name, os.path.join(OUT_DIR, "Resume.pdf"))
605
    print_download(file, "Download Full Version", "Resume.pdf", center=True)
606
def contain(name):
607
    """
608
    Main function that open each page HTML file and call other function to write data in it
609
    :param name: the name of the file that should be written
610
    :type name:str
611
    :return:None
612
    """
613
    #
614
    file = open(os.path.join(OUT_DIR, name + ".html"), "a")
615
    text_file = open(os.path.join(DOC_DIR, name + ".txt"), "r")
616
    files.append(file)
617
    files.append(text_file)
618
619
    if name.upper() == "INDEX":
620
        build_index(file)
621
    elif name.upper() == "RESUME":
622
        build_resume(file)
623
624
    print_text(text_file, file)
625
    if name.upper() == "INDEX":
626
        print_adv(file)
627
def clear_folder(path):
628
    """
629
    This function get path of folder and delete its contains
630
    :param path: the path that gonna be deleted.
631
    :type path:str
632
    :return: None
633
    """
634
    if os.path.exists(path):
635
        list_of_files = os.listdir(path)
636
        for file in list_of_files:
637
            os.remove(os.path.join(path, file))
638
    else:
639
        os.mkdir(path)
640
def print_warning():
641
    """
642
     Print warnings!
643
    :return:None
644
    """
645
    print(str(len(warnings)) + " Warning , 0 Error")
646
    show_items(warnings)
647
def get_color_code():
648
    """
649
    Ask for selecting color of text and background
650
    :return list: background and text color
651
    >>> get_color_code()
652
    0 - White
653
    1 - Black
654
    2 - Purple
655
    3 - Yellow
656
    4 - Orange
657
    5 - Green
658
    6 - Blue
659
    Please enter your background color : 1
660
    Please enter your text color : 2
661
    [1, 2]
662
    """
663
    for i, item in enumerate(COLOR_BOX):
664
        print(i, "-", item)
665
    back_color_code = int(input("Please enter your background color : "))
666
    if back_color_code not in range(7):
667
        back_color_code = 0
668
    text_color_code = int(input("Please enter your text color : "))
669
    if text_color_code not in range(7):
670
        text_color_code = 1
671
    return [back_color_code, text_color_code]
672
def color_code_map():
673
    """
674
    Check and insert colors that is chosen.
675
    :return list: background and text color
676
    """
677
    [back_color_code, text_color_code] = get_color_code()
678
    if text_color_code == back_color_code:
679
        warnings.append(WARNING_DICT["color_warning"] + " Your text color and background color are same!!")
680
    background_color = COLOR_BOX[back_color_code]  # convert code to color string in COLOR_BOX
681
    text_color = COLOR_BOX[text_color_code]  # convert code to color string in COLOR_BOX
682
    return [background_color, text_color]
683
def css_font(font_folder):
684
    """
685
     Search and file all fonts.
686
    :param font_folder: the folder to search.
687
    :type font_folder:list
688
    :return list : font_flag and the current format
689
    """
690
    font_flag = 0  # 0 If there is no font file in font_folder
691
    current_FONT_FORMAT = None
692
    for i in font_folder:
693
        for j in FONT_FORMAT:  # search for other font format in font box
694
            if i.lower().find(j) != -1:  # If there is a font in font folder
695
                shutil.copyfile(os.path.join(FONT_DIR, i),
696
                                os.path.join(OUT_DIR, "qpage" + j))  # copy font file to output folder
697
                font_flag = 1  # Turn Flag On
698
                current_FONT_FORMAT = j  # font format of current selected font for css editing
699
    return [font_flag, current_FONT_FORMAT]
700
def font_creator(css_file, font_section):
701
    """
702
     Ask and Select font.
703
    :param css_file: the file that font css will be added to.
704
    :param font_section: the font section of css file
705
    :type css_file:_io.TextIOWrapper
706
    :type font_section:str
707
    :return font_section: the font section of css after edit as string
708
    """
709
    font_folder = os.listdir(FONT_DIR)
710
    details = css_font(font_folder)
711
    current_FONT_FORMAT = details[1]
712
    font_flag = details[0]
713
    if font_flag == 1:  # check flag if it is 1
714
        css_file.write(
715
            "@font-face{\nfont-family:qpagefont;\nsrc:url(qpage"
716
            + current_FONT_FORMAT
717
            + ");\n}\n")  # Write font-face in html
718
719
        font_section = "font-family:qpagefont;\n"  # Update Font Section For Body Tag
720
        for i, item in enumerate(FONTSTYLE_BOX):
721
            print(i, "-", item)
722
        font_style = int(input(" Please choose your font style "))
723
        if font_style < len(FONTSTYLE_BOX):
724
            font_style = FONTSTYLE_BOX[font_style]
725
        else:
726
            font_style = "normal"
727
        font_section = font_section + "font-style:" + font_style + ";\n"
728
    else:
729
        warnings.append(WARNING_DICT["font_warning"] + " There is no specific font set for this website!!")
730
    return font_section
731
def css_creator():
732
    """
733
    Ask For background and text color in and make css base
734
    :return:None
735
     """
736
    font_section = 'font-family : Georgia , serif;\n'
737
    colors = color_code_map()
738
    background_color = colors[0]
739
    text_color = colors[1]
740
741
    css_file = open(os.path.join(OUT_DIR, "styles.css"), "w")  # open css file
742
    font_section = font_creator(css_file, font_section)
743
744
    css_file.write(
745
        ".body_tag{\n"
746
        + "background-color:"
747
        + background_color
748
        + ";\n"
749
        + font_section
750
        + CSS_MARGIN
751
        + CSS_ANIMATION_1
752
        + "}\n")  # write body tag
753
    css_file.write(".color_tag{\n" + "color:" + text_color + ";\n}")  # write color_tag in css
754
    css_file.write(CSS_ANIMATION_2)
755
    css_file.close()  # close css file
756
def preview():
757
    """
758
    Preview website in browser
759
    :return:None
760
     """
761
    # TODO: not working on unix
762
    webbrowser.open(os.path.join(OUT_DIR, "index.html"))
763
def error_finder():
764
    """
765
    Check and find error that display it
766
    :return : error and pass vector as list
767
    """
768
    error_vector = []
769
    pass_vector = []
770
    PDF_COUNTER = 0
771
    # image_list = os.listdir(IMAGE_DIR)
772
    doc_list = os.listdir(DOC_DIR)
773
    if IMAGE_COUNTER == 1:
774
        pass_vector.append("[Pass] Your profile image in OK!!")
775
    else:
776
        error_vector.append(ERROR_DICT["image_error"] + " Your profile image is not in correct format")
777
    if len(doc_list) == 0:
778
        error_vector.append(ERROR_DICT["empty_error"] + "There is no file in doc folder ( index.txt and .pdf file in "
779
                                                        "necessary)")
780
    else:
781
        if "index.txt" in doc_list:
782
            pass_vector.append("[Pass] index.txt file OK!")
783
        else:
784
            error_vector.append(ERROR_DICT["firstpage_error"] + " index.txt is not in doc folder!")
785
        if PDF_COUNTER == 0:
786
            error_vector.append(ERROR_DICT["resume_error"] + "[Error] Where Is Your Resume File? It should be in doc "
787
                                                             "folder")
788
        else:
789
            pass_vector.append("[Pass] Your Resume File is OK!!")
790
    return [error_vector, pass_vector]
791
def icon_creator():
792
    """
793
     Find .ico file and use it as favicon of website.
794
     :return:None
795
     """
796
    icon_flag = 0
797
    for file in os.listdir(IMAGE_DIR):
798
        if file.endswith('ico'):
799
            shutil.copy(os.path.join(IMAGE_DIR, file), OUT_DIR)
800
            os.rename(os.path.join(OUT_DIR, file), os.path.join(OUT_DIR, 'favicon.ico'))
801
            icon_flag = 1
802
            break
803
    if "favicon.ico" in os.listdir(SOURCE_DIR) and icon_flag == 0:
804
        shutil.copy(os.path.join(SOURCE_DIR, "favicon.ico"), OUT_DIR)
805
        warnings.append(WARNING_DICT["icon_warning"] + " There is no icon for this website")
806
def robot_maker():
807
    """
808
     Create Robots.txt for pages
809
     :return:None
810
    """
811
    robots = open(os.path.join(OUT_DIR, "robots.txt"), "w")
812
    robots.write("User-agent: *\n")
813
    robots.write("Disallow: ")
814
    robots.close()
815
def internet(host="8.8.8.8", port=53, timeout=3):
816
    """
817
    Check Internet Connections.
818
    :param  host: the host that check connection to
819
    :param  port: port that check connection with
820
    :param  timeout: times that check the connnection
821
    :type host:str
822
    :type port:int
823
    :type timeout:int
824
    :return bool: True if Connection is Stable
825
    >>> internet() # if there is stable internet connection
826
    True
827
    >>> internet() # if there is no stable internet connection
828
    False
829
    """
830
    try:
831
        socket.setdefaulttimeout(timeout)
832
        socket.socket(socket.AF_INET, socket.SOCK_STREAM).connect((host, port))
833
        return True
834
    except Exception as ex:
835
        error_log(str(ex))
836
        return False
837
def server():
838
    """
839
    Get Server response.
840
    :return:None
841
    >>> server()
842
    Installed Saved!
843
    """
844
    # global meta_input
845
    headers = {'content-type': 'application/json', "NAME": meta_input, "VERSION": VERSION, "SYSTEM": system_details(),
846
               "IP": find_global_ip()}
847
    try:
848
        response = requests.get(SERVER_API, headers=headers)
849
        if response.status_code == 200:
850
            print("Installed Saved!")
851
    except Exception as e:
852
        error_log(str(e))
853
def version_control():
854
    """
855
     Check and update version status
856
     :return:None
857
    """
858
    try:
859
        # print("Check for new VERSION . . .")
860
        # print_line(70)
861
        VERSION_pattern = r"last_VERSION:(.+)"
862
        if internet():
863
            response = requests.get("http://www.qpage.ir/releases.html")
864
            body = response.text
865
            last_VERSION = float(re.findall(VERSION_pattern, body)[0][:-3])
866
            if last_VERSION > float(VERSION):
867
                print_line(70)
868
                print("**New VERSION Of Qpage Is Available Now (VERSION " + str(last_VERSION) + ")**")
869
                print("Download Link -->" + "https://github.com/sepandhaghighi/qpage/archive/v" + str(
870
                    last_VERSION) + ".zip")
871
                print_line(70)
872
            else:
873
                # TODO : fix VERSION control else
874
                pass
875
                # print("Already Updated!!!")
876
                # print_line(70)
877
    except Exception as e:
878
        error_log(e)
879
        pass
880
def enter_to_exit():
881
    """
882
    Quit Project by pressing a key.
883
    :return:None
884
    """
885
886
    print_line(70, "*")
887
    response = input("Enter [R] for restart Qpage and any other key to exit : ")
888
    if response.upper() != "R":
889
        sys.exit()
890
def wait_func(iteration=2):
891
    """
892
    Wait for-in range Iteration.
893
    :param iteration: the amount of wait.
894
    :type iteration:int
895
    :return:None
896
    >>> wait_func(4)
897
    .
898
    .
899
    .
900
    .
901
    >>> wait_func()
902
    .
903
    .
904
    """
905
906
    for _ in range(iteration):
907
        time.sleep(1)
908
        print(".")
909
if __name__=="__main__":
910
    doctest.testmod()
911