├── .github └── workflows │ └── django.yml ├── .gitignore ├── .pre-commit-config.yaml ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── accounts ├── __init__.py ├── admin.py ├── apps.py ├── forms.py ├── migrations │ ├── 0001_initial.py │ └── __init__.py ├── models.py ├── templates │ ├── profile.html │ └── registration │ │ ├── change_password.html │ │ ├── login.html │ │ └── signup.html ├── tests │ ├── __init__.py │ ├── test_forms.py │ ├── test_models.py │ └── test_views.py ├── urls.py └── views.py ├── codehub ├── __init__.py ├── asgi.py ├── settings.py ├── urls.py └── wsgi.py ├── locale └── fa │ └── LC_MESSAGES │ ├── django.mo │ └── django.po ├── main ├── __init__.py ├── admin.py ├── apps.py ├── constants.py ├── context_processor.py ├── forms.py ├── migrations │ ├── 0001_initial.py │ └── __init__.py ├── models.py ├── serializers.py ├── static │ ├── css │ │ └── style.css │ ├── fonts │ │ ├── ubuntu │ │ │ ├── UbuntuMono-Bold.ttf │ │ │ ├── UbuntuMono-BoldItalic.ttf │ │ │ ├── UbuntuMono-Italic.ttf │ │ │ └── UbuntuMono-Regular.ttf │ │ └── vazir │ │ │ ├── Farsi-Digits │ │ │ ├── Vazir-Black-FD.eot │ │ │ ├── Vazir-Black-FD.ttf │ │ │ ├── Vazir-Black-FD.woff │ │ │ ├── Vazir-Black-FD.woff2 │ │ │ ├── Vazir-Bold-FD.eot │ │ │ ├── Vazir-Bold-FD.ttf │ │ │ ├── Vazir-Bold-FD.woff │ │ │ ├── Vazir-Bold-FD.woff2 │ │ │ ├── Vazir-Light-FD.eot │ │ │ ├── Vazir-Light-FD.ttf │ │ │ ├── Vazir-Light-FD.woff │ │ │ ├── Vazir-Light-FD.woff2 │ │ │ ├── Vazir-Medium-FD.eot │ │ │ ├── Vazir-Medium-FD.ttf │ │ │ ├── Vazir-Medium-FD.woff │ │ │ ├── Vazir-Medium-FD.woff2 │ │ │ ├── Vazir-Regular-FD.eot │ │ │ ├── Vazir-Regular-FD.ttf │ │ │ ├── Vazir-Regular-FD.woff │ │ │ ├── Vazir-Regular-FD.woff2 │ │ │ ├── Vazir-Thin-FD.eot │ │ │ ├── Vazir-Thin-FD.ttf │ │ │ ├── Vazir-Thin-FD.woff │ │ │ └── Vazir-Thin-FD.woff2 │ │ │ ├── Vazir-Black.eot │ │ │ ├── Vazir-Black.ttf │ │ │ ├── Vazir-Black.woff │ │ │ ├── Vazir-Black.woff2 │ │ │ ├── Vazir-Bold.eot │ │ │ ├── Vazir-Bold.ttf │ │ │ ├── Vazir-Bold.woff │ │ │ ├── Vazir-Bold.woff2 │ │ │ ├── Vazir-Light.eot │ │ │ ├── Vazir-Light.ttf │ │ │ ├── Vazir-Light.woff │ │ │ ├── Vazir-Light.woff2 │ │ │ ├── Vazir-Medium.eot │ │ │ ├── Vazir-Medium.ttf │ │ │ ├── Vazir-Medium.woff │ │ │ ├── Vazir-Medium.woff2 │ │ │ ├── Vazir-Regular.eot │ │ │ ├── Vazir-Regular.ttf │ │ │ ├── Vazir-Regular.woff │ │ │ ├── Vazir-Regular.woff2 │ │ │ ├── Vazir-Thin.eot │ │ │ ├── Vazir-Thin.ttf │ │ │ ├── Vazir-Thin.woff │ │ │ ├── Vazir-Thin.woff2 │ │ │ ├── Vazir-Variable.eot │ │ │ ├── Vazir-Variable.ttf │ │ │ ├── Vazir-Variable.woff │ │ │ └── Vazir-Variable.woff2 │ └── img │ │ ├── development-banner.png │ │ ├── download-banner.png │ │ ├── fav.ico │ │ ├── figure.png │ │ ├── home-banner.png │ │ ├── icons │ │ └── material │ │ │ ├── arduino.svg │ │ │ ├── bash.svg │ │ │ ├── c.svg │ │ │ ├── cpp.svg │ │ │ ├── csharp.svg │ │ │ ├── css.svg │ │ │ ├── dart.svg │ │ │ ├── docker.svg │ │ │ ├── go.svg │ │ │ ├── html.svg │ │ │ ├── java.svg │ │ │ ├── js.svg │ │ │ ├── json.svg │ │ │ ├── lua.svg │ │ │ ├── md.svg │ │ │ ├── mysql.svg │ │ │ ├── php.svg │ │ │ ├── python.svg │ │ │ └── rb.svg │ │ ├── logo.png │ │ ├── offcanvas.png │ │ └── solid-banner.png ├── templates │ ├── 403.html │ ├── 404.html │ ├── development.html │ ├── download.html │ └── home.html ├── templatetags │ └── markdown_extras.py ├── urls.py ├── utils.py └── views.py ├── manage.py ├── requirements.txt ├── snippets ├── __init__.py ├── admin.py ├── apps.py ├── constants.py ├── forms.py ├── migrations │ ├── 0001_initial.py │ └── __init__.py ├── models.py ├── serializers.py ├── templates │ ├── create_snippet.html │ └── snippet.html ├── tests.py ├── tests │ ├── __init__.py │ └── test_models.py ├── urls.py └── views.py ├── templates └── _base.html └── tickets ├── __init__.py ├── admin.py ├── apps.py ├── constants.py ├── forms.py ├── migrations ├── 0001_initial.py └── __init__.py ├── models.py ├── templates ├── create_ticket.html ├── ticket.html └── ticket_search_results.html ├── tests.py ├── tests ├── __init__.py └── test_models.py ├── urls.py └── views.py /.github/workflows/django.yml: -------------------------------------------------------------------------------- 1 | name: Django CI 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: ubuntu-latest 13 | strategy: 14 | max-parallel: 4 15 | 16 | steps: 17 | - uses: actions/checkout@v2 18 | - name: Set up Python 3.10 19 | uses: actions/setup-python@v3 20 | with: 21 | python-version: 3.10.2 22 | - name: Install Dependencies 23 | run: | 24 | python -m pip install --upgrade pip 25 | pip install -r requirements.txt 26 | - name: Run Tests 27 | env: 28 | SECRET_KEY: ${{ secrets.SECRET_KEY }} 29 | ADMIN_PATH: ${{ secrets.ADMIN_PATH }} 30 | run: | 31 | echo $SECRET_KEY >> .env 32 | echo $ADMIN_PATH >> .env 33 | python manage.py test --pattern="test_*.py" 34 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ngo # 2 | *.log 3 | *.pot 4 | *.pyc 5 | __pycache__ 6 | db.sqlite3 7 | media 8 | 9 | # Backup files # 10 | *.bak 11 | 12 | # If you are using PyCharm # 13 | .idea/**/workspace.xml 14 | .idea/**/tasks.xml 15 | .idea/dictionaries 16 | .idea/**/dataSources/ 17 | .idea/**/dataSources.ids 18 | .idea/**/dataSources.xml 19 | .idea/**/dataSources.local.xml 20 | .idea/**/sqlDataSources.xml 21 | .idea/**/dynamic.xml 22 | .idea/**/uiDesigner.xml 23 | .idea/**/gradle.xml 24 | .idea/**/libraries 25 | *.iws /out/ 26 | 27 | # Python # 28 | *.py[cod] 29 | *$py.class 30 | 31 | # Distribution / packaging 32 | .Python build/ 33 | develop-eggs/ 34 | dist/ 35 | downloads/ 36 | eggs/ 37 | .eggs/ 38 | lib/ 39 | lib64/ 40 | parts/ 41 | sdist/ 42 | var/ 43 | wheels/ 44 | *.egg-info/ 45 | .installed.cfg 46 | *.egg 47 | *.manifest 48 | *.spec 49 | 50 | # Installer logs 51 | pip-log.txt 52 | pip-delete-this-directory.txt 53 | 54 | # Unit test / coverage reports 55 | htmlcov/ 56 | .tox/ 57 | .coverage 58 | .coverage.* 59 | .cache 60 | .pytest_cache/ 61 | nosetests.xml 62 | coverage.xml 63 | *.cover 64 | .hypothesis/ 65 | 66 | # Jupyter Notebook 67 | .ipynb_checkpoints 68 | 69 | # pyenv 70 | .python-version 71 | 72 | # celery 73 | celerybeat-schedule.* 74 | 75 | # SageMath parsed files 76 | *.sage.py 77 | 78 | # Environments 79 | .env 80 | .venv 81 | env/ 82 | venv/ 83 | ENV/ 84 | env.bak/ 85 | venv.bak/ 86 | 87 | # mkdocs documentation 88 | /site 89 | 90 | # mypy 91 | .mypy_cache/ 92 | 93 | # Sublime Text # 94 | *.tmlanguage.cache 95 | *.tmPreferences.cache 96 | *.stTheme.cache 97 | *.sublime-workspace 98 | *.sublime-project 99 | 100 | # sftp configuration file 101 | sftp-config.json 102 | 103 | # Package control specific files Package 104 | Control.last-run 105 | Control.ca-list 106 | Control.ca-bundle 107 | Control.system-ca-bundle 108 | GitHub.sublime-settings 109 | 110 | # Visual Studio Code # 111 | .vscode/* 112 | !.vscode/settings.json 113 | !.vscode/tasks.json 114 | !.vscode/launch.json 115 | !.vscode/extensions.json 116 | .history 117 | 118 | # Custom Ignores 119 | local_settings.py 120 | static/ 121 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Will be updated soon.. 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Sadra Yahyapour 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 |
3 |
برای تغییر رمز کاربری، اینجا را کلیک کنید.
42 |{{ticket.description|truncatewords:15}}
60 |ثبت شده در {{ticket.created_on |date:'d-m-Y'}} 61 | {% for tag in ticket.tags.all %} 62 | {{tag.name}}# 64 | {% endfor %} 65 |
66 |هنوز برچسبی ایجاد نکردید! :(
72 | {% endif %} 73 |هنوز تکهکدی ایجاد نکردید! :(
93 | {% endif %} 94 | 95 |هنوز نظری ثبت نکردید! :(
113 | {% endif %} 114 | 115 |متاسفانه در حال حاضر، دسترسی شما به این صفحه مقدور نمی باشد.
8 | {% endblock %} -------------------------------------------------------------------------------- /main/templates/404.html: -------------------------------------------------------------------------------- 1 | {% extends '_base.html' %} 2 | 3 | {% block title %}صفحه مورد نظر یافت نشد{% endblock %} 4 | 5 | {% block content %} 6 |32 | ما علاوه بر تمام خدماتی که در اختیار شما قرار دادیم، یک سرویس Rest API هم برای توسعه دهندگان و برنامه نویس ها ایجاد 33 | کردیم تا به راحتی از خدمات کد هاب، روی هر پلتفورمی استفاده کنند و اپلیکیشن های خودشون رو توسعه بدن. از لیست زیر، 34 | داکیومنت مورد نظر خودتون رو بررسی کنید. 35 |
Codehub provides users/devs multiple RESTful API services. This RESTful service allows 44 | developers to work with CodeHub Web Services on any platform and machine. Make sure you follow the 45 | documentation and observe all conditions and requirements.
46 | 47 | 48 | 49 |Codehub provides users/devs multiple RESTful API services. This RESTful service allows 54 | developers to work with CodeHub Web Services on any platform and machine. Make sure you follow the 55 | documentation and observe all conditions and requirements.
56 | 57 |32 | به راحتی با استفاده از دیگر محصولات تیم کد هاب، به تمامی سرویس ها و قابلیت ها، در دیگر پلتفورم ها دسترسی داشته 33 | باشید. 34 |
35 | 36 |9 | کُد هاب (به انگلیسی CodeHub) اولین سرویس متن نشان پارسیه که بصورت متن باز در پلتفورم گیت هاب در حال توسعه و بزرگ 10 | شدنه. در توسعه این سرویس، از چارچوب Django بعنوان بکاند و Bootstrap بعنوان فرانتاند استفاده شده. 11 |
27 | کد هاب بصورت متن باز در حال توسعه هست. این به این معنیه که هر توسعه دهنده ای میتونه در گسترش این پروژه سهیم باشه. 28 | برای وارد شدن به گیت هاب این پروژه، کافیه تنها روی عکس زیر کلیک کنید. در ضمن، تمامی پول رکوئست های ساخته شده توسط 29 | شما، قابل ستایش و قدردانیه. با ستاره دادن و حمایت از پروژه، به بزرگتر شدن کامیونیتی متن باز ایران کمک کنید. 30 |
48 | نسخه قبلی کد هاب، اولین پروژه جنگویی من بعد از ۲ ماه شروع سفر من در جنگو بود. پر از باگ های امنیتی، مشکلات دیزاین 49 | و.. اما بعد از مدتی حسابی کار کردن روی نسخه جدید، با فیچر های نو و قابلیت های خفن، دوباره کد هاب رو سر پا کردم تا 50 | خدمتی (هرچند کوچک) به جامعه متن باز ایران کرده باشم. بزرگترین هدف من بعنوان توسعه دهنده اصلی کد هاب، ترویج فرهنگ 51 | نشر 52 | دانشه. 53 |
54 |من صدرا یحیی پور هستم. برنامه نویس پایتون و توسعه دهنده نرم افزار متن باز، علاقهمند به یادگیری ماشین و 55 | خالق کد هاب. برای آشنایی بیشتر با من، گیت هاب من رو از لینک زیر دنبال کنید. :)
در نهایت، بسیار سپاسگزارم از تمام کسانی که طی این سال ها حامی و مشوق من بودن و همیشه بدون هیچ چشم داشتی، در کنارم 72 | حضور داشتن. ممنونم از همه دوستانی که کد هاب رو حمایت کردن و در توسعه این پروژه، نقش داشتند.
جدید ترین برچسب ها
90 | {% for ticket in tickets %} 91 |{{snippet.description}}
36 | {% endif %} 37 | 38 | {% pygmentify linenos='inline' %} 39 |{{snippet.body}}41 | {% endpygmentify %} 42 | ثبت شده در تاریخ {{snippet.created_on | date:'d-m-Y'}} 43 | {% endblock %} -------------------------------------------------------------------------------- /snippets/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /snippets/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codehub-ir/codehub/1013325540351aadd00b13e2b873b4b768a53827/snippets/tests/__init__.py -------------------------------------------------------------------------------- /snippets/tests/test_models.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | from snippets.constants import LANGUAGES 3 | from snippets.models import Snippet 4 | 5 | 6 | class SnippetTestCase(TestCase): 7 | 8 | @classmethod 9 | def setUpTestData(cls) -> None: 10 | cls.sample = { 11 | 'title': 'simple title', 12 | 'description': 'some description', 13 | 'body': 'code snippet', 14 | 'lang': LANGUAGES[0][1], # Arduino 15 | } 16 | 17 | def setUp(self) -> None: 18 | self.snippet = Snippet.objects.create(**self.sample) 19 | 20 | def test_if_obj_returns_same_fields(self): 21 | fields = { 22 | 'title': self.snippet.title, 23 | 'description': self.snippet.description, 24 | 'body': self.snippet.body, 25 | 'lang': self.snippet.lang, 26 | } 27 | self.assertEqual(fields, self.sample) 28 | 29 | def test_sid_length(self): 30 | # nbyte is set to 5 by default 31 | # which provides an id with 10 chars 32 | self.assertEqual(len(self.snippet.id), 10) -------------------------------------------------------------------------------- /snippets/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | 3 | from .views import (SnippetAPIView, SnippetCreateAPIView, SnippetCreateView, 4 | SnippetView) 5 | 6 | urlpatterns = [ 7 | # Template URLs 8 | path('new-snippet/', SnippetCreateView.as_view(), name='new_snippet'), 9 | path('snippet/
{{event.body}}
149 |رویدادی موجود نیست!
153 | {% endif %} 154 |نوشته شده توسط {{ticket.created_by}} در {{ticket.created_on|date:'d-m-Y'}}
25 | 26 |{{comment.body}}
41 |نوشته شده توسط {{comment.created_by}} 42 | {{comment.created_on|date:'Y-m-d H:i'}} 43 |
44 |برچسب شما در دست بررسی می باشد و تا زمان تایید شدن، تنها برای شما قابل نمایش است.
54 |متاسفانه برچسب ساخته شده توسط شما، قابلیت نمایش بصورت عمومی را ندارد.
61 |برچسبی یافت نشد!
42 | {% endif %} 43 | {% endblock %} -------------------------------------------------------------------------------- /tickets/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /tickets/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codehub-ir/codehub/1013325540351aadd00b13e2b873b4b768a53827/tickets/tests/__init__.py -------------------------------------------------------------------------------- /tickets/tests/test_models.py: -------------------------------------------------------------------------------- 1 | from accounts.models import User 2 | from django.test import TestCase 3 | from tickets.models import Comment, Tag, Ticket 4 | 5 | 6 | class TagTestCase(TestCase): 7 | 8 | @classmethod 9 | def setUpTestData(cls) -> None: 10 | cls.sample = { 11 | 'name': 'AngularLA', 12 | 'description': 'a framework built in LA', 13 | } 14 | 15 | def setUp(self) -> None: 16 | self.tag = Tag.objects.create(**self.sample) 17 | 18 | def test_if_obj_returns_same_fields(self): 19 | fields = { 20 | 'name': self.tag.name, 21 | 'description': self.tag.description, 22 | } 23 | 24 | self.assertEqual(fields, self.sample) 25 | 26 | 27 | class TicketTestCase(TestCase): 28 | 29 | @classmethod 30 | def setUpTestData(cls) -> None: 31 | cls.ticket_sample = { 32 | 'title': 'Ticket Title', 33 | 'description': 'Ticket Description', 34 | } 35 | 36 | cls.user_sample = { 37 | 'username': 'johndoe', 38 | 'display_name': 'John Doe', 39 | 'email': 'john@doe.com', 40 | 'password': 'testPass123', 41 | } 42 | 43 | cls.tag_sample = { 44 | 'name': 'Tag Name', 45 | 'description': 'Tag Description', 46 | } 47 | 48 | def setUp(self) -> None: 49 | _user = User.objects.create(**self.user_sample) 50 | 51 | ''' 52 | Since the Ticket.tags is a ManyToMany field, 53 | It needs to get saved immediately right after 54 | It created. 55 | ''' 56 | _tag = Tag(**self.tag_sample) 57 | _tag.save() 58 | 59 | self.ticket = Ticket.objects.create(**self.ticket_sample) 60 | self.ticket.save() 61 | 62 | ''' 63 | Then we add those pre-built Tag objects to 64 | the Ticket object tags field. -> Ticket.tags 65 | ''' 66 | self.ticket.tags.set([_tag]) 67 | self.ticket.created_by = _user 68 | 69 | def test_obj_returns_same_fields(self): 70 | fields = { 71 | 'title': self.ticket.title, 72 | 'description': self.ticket.description, 73 | } 74 | 75 | self.assertEqual(fields, self.ticket_sample) 76 | 77 | def test_check_ticket_creator(self): 78 | self.assertEqual(self.ticket.created_by.username, 79 | self.user_sample['username']) 80 | 81 | 82 | class CommentTestCase(TestCase): 83 | 84 | @classmethod 85 | def setUpTestData(cls) -> None: 86 | cls.ticket_sample = { 87 | 'title': 'Ticket Title', 88 | 'description': 'Ticket Description', 89 | } 90 | cls.user_sample = { 91 | 'username': 'johndoe', 92 | 'display_name': 'John Doe', 93 | 'email': 'john@doe.com', 94 | 'password': 'testPass123', 95 | } 96 | cls.comment_sample = { 97 | 'body': 'Body of the comment', 98 | } 99 | 100 | def setUp(self) -> None: 101 | self.ticket = Ticket.objects.create(**self.ticket_sample) 102 | self.user = User.objects.create(**self.user_sample) 103 | 104 | self.comment_sample['ticket'] = self.ticket 105 | self.comment_sample['created_by'] = self.user 106 | 107 | self.comment = Comment.objects.create( 108 | **self.comment_sample 109 | ) 110 | 111 | def test_if_obj_returns_same_fields(self): 112 | fields = { 113 | 'body': self.comment.body, 114 | 'ticket': self.comment.ticket, 115 | 'created_by': self.comment.created_by, 116 | } 117 | 118 | self.assertEqual(fields, self.comment_sample) 119 | 120 | def test_comment_user_authority(self): 121 | self.assertEqual(self.comment.created_by, self.user) 122 | -------------------------------------------------------------------------------- /tickets/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | 3 | from .views import TicketCreateView, TicketSearchResultsView, TicketView 4 | 5 | urlpatterns = [ 6 | 7 | # Template URLs 8 | path('new-ticket/', TicketCreateView.as_view(), name='new_ticket'), 9 | path('ticket/