Completed
Push — master ( c24195...9aeb5b )
by Sepand
01:03
created

email_at()   A

Complexity

Conditions 2

Size

Total Lines 12

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