• Работает ли telegram oauth в России?

    neatsoft
    @neatsoft
    Life is too short for bad software
    Telegram login widget в России не работает, но авторизация через Telegram элементарно реализуется с помощью бота. При отправке команды бот вызывает веб-хук, передавая имя пользователя, в ответ отправляется одноразовая ссылка для входа на сайт. Бота нужно запускать на зарубежном хостинге, т.к. с него должен быть доступен api.telegram.org, пользователь может находиться где угодно.

    Вот пример на Django 2.0 (максимально упрощённый):
    1. Через @BotFather нужно создать нового бота, записать полученный token - <bot_token>
    2. Добавить команду /login с помощью /setcommands
    3. В консоли сгенерировать случайный uuid (uuidgen -r) - <webhook_token>
    4. Настроить веб-хук (вместо httpie можно использовать curl, wget, или любую другую подобную утилиту):
      http "https://api.telegram.org/bot<bot_token>/setWebhook?url=https://<domain_name>/bot/<webhook_token>/"

    5. Внести необходимые изменения в проект
    6. Если используется DatabaseCache, инициализировать таблицу в базе данных:
      ./manage.py createcachetable

    .

    settings.py
    ...
    TELEGRAM_BOT_ACCESS_TOKEN = <bot_token>
    TELEGRAM_BOT_WEBHOOK_TOKEN = <webhook_token>
    TELEGRAM_BOT_OTP_TIMEOUT = 120
    
    USE_X_FORWARDED_HOST = True
    
    CACHES = {
        'default': {
            'BACKEND': 'django.core.cache.backends.db.DatabaseCache',
            'LOCATION': 'django_cache',
        }
    }
    ...


    urls.py
    ...
    from .views import BotView, LoginView
    
    
    urlpatterns = [
        ...
        path('bot/<uuid:token>/', BotView.as_view()),
        path('login/<uuid:otp>/', LoginView.as_view(), name='login'),
    ]


    views.py
    import json
    import requests
    import uuid
    
    from django.conf import settings
    from django.contrib.auth import login
    from django.contrib.auth.models import User
    from django.core.cache import cache
    from django.http import HttpResponse, HttpResponseNotFound, HttpResponseRedirect
    from django.urls import reverse
    from django.utils.decorators import method_decorator
    from django.views import View
    from django.views.decorators.csrf import csrf_exempt
    from django.views.generic import TemplateView
    
    ...
    
    @method_decorator(csrf_exempt, name='dispatch')
    class BotView(View):
        def post(self, request, token):
            if str(token) != settings.TELEGRAM_BOT_WEBHOOK_TOKEN:
                return HttpResponseNotFound()
    
            params = json.loads(request.body)
            message = params['message']
    
            if message.get('text') == '/login':
                user = message['from']
                chat_id = user['id']
                data = {
                    'username': user['username'],
                    'first_name': user.get('first_name', ''),
                    'last_name': user.get('last_name', ''),
                }
    
                otp = uuid.uuid4()
                cache.set(otp, data, settings.TELEGRAM_BOT_OTP_TIMEOUT)
                path = reverse('login', args=[otp])
                login_url = request.build_absolute_uri(path)
    
                url = 'https://api.telegram.org/bot{}/sendMessage?chat_id={}&text={}'.format(
                    settings.TELEGRAM_BOT_ACCESS_TOKEN,
                    chat_id,
                    login_url,
                )
    
                requests.get(url, timeout=10)
    
            return HttpResponse('')
    
    
    class LoginView(TemplateView):
        template_name = 'login.html'
    
        def dispatch(self, request, otp):
            self.data = cache.get(otp, {})
            return super().dispatch(request, otp)
    
        def get_context_data(self, **kwargs):
            context = super().get_context_data(**kwargs)
            context['data'] = self.data
            return context
    
        def post(self, request, otp):
            cache.delete(otp)
    
            username = self.data.get('username')
            if not username:
                return HttpResponseRedirect(request.path)
    
            user, created = User.objects.update_or_create(
                username=username,
                defaults={
                    'first_name': self.data.get('first_name', ''),
                    'last_name': self.data.get('last_name', ''),
                },
            )
            login(request, user)
    
            path = reverse('home')
            return HttpResponseRedirect(path)


    templates/login.html
    {% extends 'bootstrap4/bootstrap4.html' %}
    
    {% block bootstrap4_content %}
    
    <div class="container">
    
      <div style="padding:5rem; text-align:center;">
        {% if not data %}
          <h1>This url invalid or expired.</h1>
        {% else %}
          <h1>Login as {{ data.username }}</h1>
          <form action="" method="post">
            {% csrf_token %}
            <button type="submit" class="btn btn-primary btn-lg btn-block">
              Login
            </button>
          </form>
        {% endif %}
      </div>
    
    </div>
    
    {% endblock %}
    Ответ написан
    Комментировать
  • Как разделить доли в ИТ-стартапе?

    Robur
    @Robur
    Знаю больше чем это необходимо
    Есть разные схемы - статей достаточно в интернете.
    Например captable.

    олжны ли мы распределить все 100% или нужно распределить 40-50%, а остальное выделить на опционы для будущих сотрудников и инвесторов?


    Можете и так и так. Разделяйте все 100%, как надо будет выделять новые доли, размывайте свои pro rata

    Нужно ли ставить ограничения на выход из проекта

    Ограничения вы вряд ли поставите, но можете обговорить условия выхода. В самом простом виде для этого есть клифф и вестинг на долю. + отказ от всяких прав на интеллектуальную собственность
    Ответ написан
    Комментировать
  • Как разделить доли в ИТ-стартапе?

    saboteur_kiev
    @saboteur_kiev
    software engineer
    Отсюда возник вопрос: как правильно разделить доли в стартапе?


    Давайте предположим, что ваш стартап через 1-2 года полностью пролетел. Все потратили свои усилия.
    Как вы будете делить затраты и решать кто кому чего должен возместить за потраченные усилия?

    Сейчас вы делите непонятно что. Если вы считаете, что ваш проект мегауспешный и все в нем получится, сделайте бизнес план, посчитайте предполагаемую прибыль и просто одолжите деньгам, чтобы нанять обычных людей за зарплату.
    Если считаете, что проект может провалиться, то задумайтесь еще раз что вы будете делать когда провалится.

    Соберитесь все вместе и решите между собой. Общих правил тут не существует.
    Ответ написан
    3 комментария
  • Как разделить доли в ИТ-стартапе?

    DMGarikk
    @DMGarikk
    Software Developer
    друзья и родственники, которые обладают в разной степени необходимыми навыками

    первый и основной способ завалить бизнес, взять друзей и родственников
    Нужно ли ставить ограничения на выход из проекта?

    расстреливать будете или отбирать квартиру? :)
    ===
    вопросы не глупые, но только ответов однозначно правильных на них нет, вы практически гарантированно столкнетесь с дележкой и проблемами и мыслями "зачем мы вообще на это решились и почему васян не подписывает согласие на продажу фирмы - мы же обанкротимся!"

    У нас есть возможность набрать разработчиков в проект, но мы должны понять как правильно из мотивировать.

    платить зарплату, достаточную и вовремя. работать за морковку в стартапе с непонятной перспективой, это такая себе мотивация... прокатывает только для студентов без опыта которых мама кормит или почемуто много лишних денег (а когда они кончаются, начинаются проблемы, в т.ч. у фирмы)
    Ответ написан
    2 комментария
  • Ошибка redux Error: Actions must be plain objects. Use custom middleware for async actions?

    Вы создаете стор в отдельном файле. Там миддлвар подключается.
    Но далее в index.js вы создаете другой стор, где миддлваров уже нет. И в Provider передаете именно его.
    Ответ написан
    1 комментарий
  • Как настроить Heroku c NIC RU?

    В панели Ру-Центра, если мне не изменяет память, нужно использовать канонический вид доменных имен. Т.е. ваша запись
    "www CNAME myapp.herokuapp.com"
    должна быть такой
    "www CNAME myapp.herokuapp.com."
    Обратите внимание на точку в конце.
    Ответ написан
    1 комментарий
  • Как в react-select передать массив для свойства isOptionDisabled?

    rockon404
    @rockon404 Куратор тега React
    Frontend Developer
    Вы должны передавать в isOptionDisabled функцию, которая принимает первым аргументом опцию и возвращает Boolean.

    createIsOptionDisabled = disOptions => option =>
      disOptions.some(({ value }) => value === option.value);


    return (
      <Select
        options={options}
        isOptionDisabled={this.createIsOptionDisabled(disOptions)}
      />
    );
    Ответ написан
    Комментировать
  • Как в react-select передать массив для свойства isOptionDisabled?

    0xD34F
    @0xD34F
    Не надо никаких массивов никуда передавать. Можно указать свойство isDisabled:

    class App extends Component {
      state = {
        options: [
          { value: "chocolate", label: "Chocolate" },
          { value: "strawberry", label: "Strawberry", isDisabled: true },
          { value: "vanilla", label: "Vanilla" },
        ],
      }
    
      render() {
        return (
          <Select
            options={this.state.options}
          />
        );
      }
    }

    Но если кровь из носу нужен отдельный массив и метод для проверки, то можно как-нибудь так, например:

    class App extends Component {
      state = {
        options: [
          { value: "chocolate", label: "Chocolate" },
          { value: "strawberry", label: "Strawberry" },
          { value: "vanilla", label: "Vanilla" }
        ],
        disabled: [ 'chocolate', 'vanilla' ],
      }
    
      isOptionDisabled = option => this.state.disabled.includes(option.value)
    
      render() {
        return (
          <Select
            options={this.state.options}
            isOptionDisabled={this.isOptionDisabled}
          />
        );
      }
    }
    Ответ написан
    Комментировать
  • Как из node.js эмитить через socket.io данные из ответа с интервалами?

    rockon404
    @rockon404
    Frontend Developer
    Вероятно, это нужно делать как-то по другому. Но я не приложу ума как это сделать

    Вы сейчас, наверное, будете сильно удивлены, но для соединения с помощью Socket.IO, надо подключить и использовать библиотеку Socket.IO.

    Изучить вопрос самостоятельно можно по этой ссылке.

    Ошибка у вас из-за неправильного использования setInterval, вы вместо колбека передаете туда результат выполнения send.

    Вместо:
    setInterval(foo(bar), duration);

    Надо:
    setInterval(() => {
      foo(bar);
    }, duration);


    Ну и для возможности остановить его выполнение его надо хранить и чистить по определенному условию:
    const interval = setInterval(() => {
      foo(bar);
      if (someCondition()) {
        clearInterval(interval);
      }
    }, duration);
    Ответ написан
    2 комментария
  • Для чего используется каррирование (карринг) в реальных задачах?

    suguby
    @suguby
    программист, python, django, mysql, git, hg, linux
    Предположим есть функция, которая берет много параметров, а первый параметр - имя класса формы (в джанго)
    def cool_staff(form_class, inits, defaults, user, other_param):
        # много строчек кода

    и вы вдруг обнаруживаете что в вашем коде куча вызовов, у которых первый параметр одинаков.
    ...
    res = cool_staff(form_class=MainForm, inits={a:1, b:3}, defaults=[1,2,3], ...)
    ...
    res = cool_staff(form_class=MainForm, inits={a:100500, b:42}, defaults=[3,2,1], ...)
    ...

    Тогда делаете так:
    main_cool_staff = lambda **kwargs: cool_staff(form_class=MainForm, **kwargs)

    и ваши вызовы упрощаются
    ...
    res = main_cool_staff(inits={a:1, b:3}, defaults=[1,2,3], ...)
    ...
    res = main_cool_staff(inits={a:100500, b:42}, defaults=[3,2,1], ...)
    ...

    было в реальном проекте.
    UPD. Такая форма карринга не сработает для неименованных параметров
    main_cool_staff = lambda *args, **kwargs: cool_staff(form_class=MainForm, *args, **kwargs)

    поэтому используйте всегда именованные параметры, это хороший стиль.

    UPD2. Еще подсказали вариант
    import functools
    main_cool_staff = functools.partial(cool_staff, MainForm)

    работает и с неименованными параметрами. Спасибо Андрей Дугин
    Ответ написан
    6 комментариев
  • Есть ли готовые библиотеки для распознавания объектов и лиц на картинках?

    inoise
    @inoise
    Solution Architect, AWS Certified, Serverless
    Ответ написан
    Комментировать
  • Как разобраться с авторизацией в Node.js?

    @Abcdefgk
    Ну, запугали человека - криптография-шриптография.
    Модуль passport - для того и готовый модуль, что он сам всю эту криптографию-шмиптографию сделает. Просто нужно освоить несколько пунктов.
    1. Установить в проект и настроить модули express-session и coockie-parser
    Без них passport не будет работать - а в чём же будет тогда смысл его работы, если он в сессию и записывает юзера после регистрации.авторизации? ("сессия" - это специальный подобъект в объекте request - req.session - куда passport сам вписывает под-объект user после авторизации)
    2. Разобраться, что passport - это общий модуль, который обеспечивает работу дополнительных модулей, в которых содержатся, как раз, всякие разные стратегии авторизации - локальная стратегия, через Фейсбук (passport-facebook), через Гугол (passport-google-oauth) и т.д.
    3. Для авторизаций через соцсети нужно в каждом случае поразбираться, как в них создавать "приложения" - оттуда для стратегий нужно будет брать ID юзера и Key, которые эти доп-модули будут запрашивать.
    4. Создаётся один большой файл-модуль для авторизации - типа auth.js - куда реквайрится сам passport плюс реквайрятся нужные (по желанию) стратегии. Типа вот так выглядит верхушка файла:
    var passport = require('passport')
    , FacebookStrategy = require('passport-facebook').Strategy
    , GoogleStrategy = require('passport-google-oauth').OAuth2Strategy;
    и для каждой из стратегий пишется код, который уже весь есть в документации модуля passport - его нужно оттуда взять и в нём, конечно, поразбираться. Не в криптографии-шриптогравии, а в этом конкретном коде.
    (Ну, и книжку внимательно изучить - я говорил в другом месте, какую)
    Ответ написан
    5 комментариев
  • Где почитать про правильную архитектуру приложения?

    myjcom
    @myjcom
    MERN Stack Front To Back: Full Stack React, Redux & Node.js
    Год выпуска: 2018
    Производитель: Udemy
    Сайт производителя: https://www.udemy.com/mern-stack-front-to-back
    Автор: Brad Traversy
    Продолжительность: 16,5 часов
    Язык: Английский

    тут ангуляр, но сути это не меняет.
    Стек MEAN. Mongo, Express, Angular, Node
    Год издания: 2017
    Автор: Холмс С.
    Издательство: Питер
    ISBN: 978-5-496-02459-4
    Язык: Русский

    В июне должно выйти 2 издание на английском.
    Ответ написан
    Комментировать
  • Где почитать про правильную архитектуру приложения?

    tsepen
    @tsepen
    Frontend developer
    Вот отличный boilerplate по данному стеку, просто посмотри реализацию или сразу используй в своем проекте
    Ответ написан
    Комментировать
  • Как перенести метод оплаты из woocommerce WP на другой сайт?

    TTkachev
    @TTkachev
    PHP + Python + JavaScript + ObjectiveC
    Просто перенести папку плагина и включить плагин в админпанели, разделе плагины.
    Ответ написан
    3 комментария
  • Как натянуть лендинг на Wordpress?

    ya-vitaliy
    @ya-vitaliy
    Верстаю... + wordpress и пробую Laravel
    Как я обычно делаю. Создаю простую страницу в админке, далее назначаю в настройках ее как статическую, чтобы она отображалась на главной при заходе на сайт. Потом использую плагин ACF и для этой страницы добавляю нужные мне секции с дополнительными полями.
    Но конечно нужно смотреть на лендинг вцелом. Допусти если у вас будет секция с отзывами с кнопкой смотреть все отзывы, то лучше их (отзывы) сделать отдельным типом записей, это позволит вам более гибко, рассширять сайт в будущем. В общем нужно смотреть макет и анализировать будущее развитие это сайта.
    Ответ написан
    1 комментарий
  • Не применяются промокоды(купоны) на Opencart, почему и как быть?

    Palych_tw
    @Palych_tw
    Типа веб-разработчик
    Смотрите в админке пункт "учитывать в заказе" и измените порядок сортировки.
    Ответ написан
    5 комментариев
  • Реально ли совмещение дизайнера и фронтэнд разработчика?

    Chipr
    @Chipr
    UX/UI designer
    В нашей компании UX/UI дизайнер развивается скорее больше в сторону PM или бизнес-аналитика, т.к. больше работы с клиентом. Базовых знаний верстки вполне достаточно, чтобы не получать косых взглядов от отдела разработки. В любом случае, всегда можно пообщаться с ребятам из фронта, если сомневаешься в реализации. Наши фронты всегда помогают и объясняют. Они крутаны.

    P.S. Я бы не слушал человека, который в 2018 году говорит, что дизайнеру необходимо знать фотошоп:)
    Ответ написан
    3 комментария