Completed
Push — master ( 0cb8d3...932688 )
by Sepand
01:19
created

create_badge()   B

Complexity

Conditions 3

Size

Total Lines 25

Duplication

Lines 0
Ratio 0 %

Importance

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