Проектируем все в FIGMA, доступ к дизайну в Figma тоже отдам бесплатно.
Проектируем все в FIGMA, доступ к дизайну в Figma тоже отдам бесплатно.

Линус Торвальдс: "Я создаю Linux не ради денег, а потому что это весело. Это как играть в Lego, только на уровне операционной системы."
Эти слова как нельзя лучше отражают дух сообщества открытого исходного кода, где разработка — это не просто работа, а страсть и возможность сделать мир лучше.

Именно с этой цитаты у меня в голове живет идея создать что-то для мирового свободного сообщества.

Сегодня я хочу рассказать о своем проекте — современном личном кабинете, который интегрируется с модулями ISP system, такими как Billmanager и VMmanager. Этот проект будет распространяться абсолютно бесплатно под лицензией GNU GPL, и я надеюсь, что он станет моим вкладом в сообщество свободного ПО.

Что делает мой dashboard blackmore уникальным?

  1. User-friendly дизайн:
    Современный и минималистичный интерфейс, который делает работу с Billmanager и другими модулями простой и приятной. Хочу сделать комплимент организации timeweb за лучший и приятный дизайн управления системой isp.

  2. Интеграция с ISP system:
    Полная совместимость с популярными модулями, такими как Billmanager, VMmanager и другими, что позволяет управлять всеми процессами из одного места.

  3. Открытый исходный код:
    Проект будет распространяться под лицензией GNU GPL, что означает свободу использования, модификации и распространения. Репозитойрий и figma макет будут доступны для загрузки.

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

Работаете по ночам на oled дисплее? тогда черный цвет для Вас будет экономить электроэнергию.
Работаете по ночам на oled дисплее? тогда черный цвет для Вас будет экономить электроэнергию.

Глава: Техническая составляющая: почему Node.js?

Простота и доступность кода

Одним из ключевых принципов моего проекта является простота. Я убежден, что если код будет слишком сложным, то сообщество вокруг него не сформируется. Вместо этого, пользователи будут просто использовать "дефолтную" версию, не внося изменений и не создавая интересных форков. Чтобы избежать этого, я уделяю особое внимание следующим аспектам:

  1. Чистый и понятный код:
    Я стараюсь писать код, который легко читать и понимать. Это включает в себя использование понятных имен переменных и функций, а также следование принципам DRY (Don't Repeat Yourself) и KISS (Keep It Simple, Stupid).

  2. Глубокие комментарии:
    Каждая сложная часть кода сопровождается подробными комментариями, которые объясняют, что происходит и почему это сделано именно так. Это помогает другим разработчикам быстрее разобраться в проекте и внести свои улучшения.

  3. Модульная структура:
    Проект разделен на модули, каждый из которых отвечает за определенную функциональность. Это не только упрощает разработку, но и позволяет другим разработчикам легко добавлять новые функции или изменять существующие.

  4. Документация:
    Помимо комментариев в коде, я создаю подробную документацию, которая объясняет, как настроить проект, как он работает и как можно его расширить. Это особенно важно для новичков, которые только начинают знакомиться с проектом.

  5. Примеры использования:
    В проекте будут включены примеры использования API и других ключевых функций. Это поможет разработчикам быстрее понять, как интегрировать dashboard в свои проекты.

Почему это важно?

Как сказал один из разработчиков открытого ПО: "Простота — это не отсутствие сложности, а ясность и понятность." Я верю, что только простой и хорошо документированный проект может привлечь сообщество и вдохновить других на создание форков. Если код будет слишком сложным, то даже самые заинтересованные разработчики могут отказаться от участия в проекте.

// Этот модуль отвечает за интеграцию с Billmanager API
// Используется библиотека Axios для отправки HTTP-запросов

const axios = require('axios');

/**
 * Функция для получения информации о счете пользователя
 * @param {string} userId - ID пользователя
 * @returns {Promise} - Возвращает данные о счете или ошибку
 */
async function getUserBill(userId) {
    try {
        const response = await axios.get(`https://api.billmanager.com/user/${userId}/bill`);
        return response.data;
    } catch (error) {
        console.error('Ошибка при получении данных:', error);
        throw error;
    }
}

module.exports = { getUserBill };

Простота и доступность кода — это не просто пожелание, это необходимость для успешного open-source проекта. Я стремлюсь сделать свой dashboard максимально понятным и дружелюбным для других разработчиков, чтобы каждый мог легко внести свой вклад или создать собственный форк. В конце концов, именно сообщество делает open-source проекты по-настоящему живыми и развивающимися.

Окно авторизации, многие проекты хостинга просто используют дефолтную авторизацию от билл менеджера, и даже не меняют логотип и фон на свой, хотя это есть в базовых настройках
Окно авторизации, многие проекты хостинга просто используют дефолтную авторизацию от билл менеджера, и даже не меняют логотип и фон на свой, хотя это есть в базовых настройках

Глава: Реализация авторизации в dashboard

Авторизация — это ключевой элемент любого приложения, особенно если оно взаимодействует с внешними системами, такими как Billmanager. В этой главе я расскажу, как будет реализована авторизация в моем dashboard, начиная с верстки макета и заканчивая интеграцией с API Billmanager.

1. Верстка макета авторизации

Макет авторизации был создан в Figma и включает следующие элементы:

  • Поля ввода для email и пароля.

  • Кнопка "Войти".

  • Ссылки "Забыли пароль?" и "Регистрация".

Для верстки этого макета я использую React (или Vue.js, если вы предпочитаете этот фреймворк) и библиотеку компонентов, такую как Material-UI или Tailwind CSS, чтобы сделать интерфейс современным и отзывчивым.

Пример верстки на React:

import React, { useState } from 'react';

const LoginForm = () => {
    const [email, setEmail] = useState('');
    const [password, setPassword] = useState('');
    const [rememberMe, setRememberMe] = useState(false);

    const handleLogin = async () => {
        // Логика авторизации через API
        console.log('Email:', email, 'Password:', password);
    };

    return (
        <div className="min-h-screen bg-gray-100 flex items-center justify-center">
            <div className="bg-white p-8 rounded-lg shadow-md w-80">
                {/* Заголовок */}
                <div className="text-center mb-8">
                    <div className="text-2xl font-bold text-gray-800 mb-2">
                        BLACKMORE
                        <span className="text-blue-600">CLOUD</span>
                    </div>
                    <div className="text-sm text-gray-500">
                        GNU GPL DASHBOARD
                    </div>
                    <div className="mt-2 text-3xl text-gray-400">#BXoA</div>
                </div>

                {/* Поля ввода */}
                <div className="space-y-4">
                    <input
                        type="email"
                        placeholder="Введите Email"
                        className="w-full px-3 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-400"
                        value={email}
                        onChange={(e) => setEmail(e.target.value)}
                    />
                    <input
                        type="password"
                        placeholder="Введите пароль"
                        className="w-full px-3 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-400"
                        value={password}
                        onChange={(e) => setPassword(e.target.value)}
                    />
                </div>

                {/* Чекбокс и напоминание */}
                <div className="flex items-center justify-between mt-4">
                    <label className="flex items-center space-x-2">
                        <input
                            type="checkbox"
                            checked={rememberMe}
                            onChange={(e) => setRememberMe(e.target.checked)}
                            className="form-checkbox h-4 w-4 text-blue-600"
                        />
                        <span className="text-sm text-gray-600">Запомнить?</span>
                    </label>
                    <a href="#" className="text-sm text-blue-600 hover:underline">
                        Напомнить?
                    </a>
                </div>

                {/* Кнопка входа */}
                <button
                    onClick={handleLogin}
                    className="w-full mt-6 bg-blue-600 text-white py-2 rounded-lg hover:bg-blue-700 transition-colors"
                >
                    войти
                </button>

                {/* Регистрация */}
                <div className="mt-4 text-center">
                    <span className="text-sm text-gray-600">НЕТ АККАУНТА? </span>
                    <a href="#" className="text-blue-600 hover:underline">РЕГИСТРАЦИЯ</a>
                </div>
            </div>
        </div>
    );
};

export default LoginForm;

Интеграция с API Billmanager

Для авторизации в Billmanager используется API, который поддерживает несколько методов. Я выбрал метод авторизации с использованием уникального номера сессии, так как он наиболее подходит для веб-приложений.

Шаги авторизации:

  1. Отправка запроса на авторизацию:
    Пользователь вводит email и пароль, которые отправляются на сервер Billmanager для получения номера сессии.

  2. Получение номера сессии:
    Если авторизация успешна, сервер возвращает XML-документ с номером сессии.

  3. Использование номера сессии:
    Номер сессии используется для всех последующих запросов к API Billmanager.

const axios = require('axios');

async function login(username, password) {
    try {
        const response = await axios.get('https://IP-адрес:1500/billmgr', {
            params: {
                out: 'xml',
                func: 'auth',
                username: username,
                password: password,
            },
        });

        // Парсим XML-ответ
        const parser = new DOMParser();
        const xmlDoc = parser.parseFromString(response.data, 'text/xml');
        const sessionId = xmlDoc.querySelector('auth').textContent;

        console.log('Сессия успешно создана. ID сессии:', sessionId);
        return sessionId;
    } catch (error) {
        console.error('Ошибка авторизации:', error);
        throw error;
    }
}

3. Хранение номера сессии

Номер сессии необходимо хранить на клиенте (например, в localStorage или cookies) и передавать с каждым запросом к API. Это можно сделать следующим образом:

// Сохраняем номер сессии в localStorage
localStorage.setItem('sessionId', sessionId);

// Используем номер сессии для запросов
async function makeRequest(func, params) {
    const sessionId = localStorage.getItem('sessionId');
    const response = await axios.get('https://IP-адрес:1500/billmgr', {
        params: {
            auth: sessionId,
            out: 'xml',
            func: func,
            ...params,
        },
    });
    return response.data;
}

4. Завершение сессии

Чтобы завершить сессию пользователя, необходимо отправить запрос на удаление сессии:

async function logout(sessionId) {
    try {
        await axios.get('https://IP-адрес:1500/billmgr', {
            params: {
                func: 'session.delete',
                elid: sessionId,
                sok: 'ok',
            },
        });
        console.log('Сессия успешно завершена.');
    } catch (error) {
        console.error('Ошибка завершения сессии:', error);
    }
}

5. Обработка ошибок

Важно предусмотреть обработку ошибок, таких как:

  • Неверный email или пароль.

  • Истекший номер сессии.

  • Ограничения доступа.

Пример обработки ошибок:

try {
    const sessionId = await login(email, password);
    // Дальнейшие действия
} catch (error) {
    if (error.response && error.response.status === 401) {
        alert('Неверный email или пароль');
    } else {
        alert('Произошла ошибка. Попробуйте еще раз.');
    }
}

Конечно в нашем дашборде будет мини-админ панель, что бы можно было автоматизировать процесс добавления и даже установки модулей isp.

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

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

Комментарии (6)


  1. Prepodobnyi
    17.02.2025 14:57

    Ждем всей семьей! Очень многообещающе.


  1. zorn-v100500
    17.02.2025 14:57

    // Используется библиотека Axios для отправки HTTP-запросов
    const axios = require('axios');

    А что еще может делать require('axios') ?

    /**

    * Функция для получения информации о счете пользователя

    * @param {string} userId - ID пользователя

    * @returns {Promise} - Возвращает данные о счете или ошибку

    */

    async function getUserBill(userId)

    Да ладно, по названиям не понятно ?

    КО рукоплещет (на самом деле возвращает промис, но да ладно).

    ...

    Начал писать коментарий, а потом решил найти ссылку на код и наткнулся на

    Для верстки этого макета я использую React (или Vue.js, если вы предпочитаете этот фреймворк)

    ГПТ мусор в квадрате.


  1. gavrilovegor519
    17.02.2025 14:57

    Лучше Vaadin'а ничего нету :D

    Пишешь фуллстек на Java (которая именно Java, а не JS), вёрстку + бэковую часть делаешь прям в Java-классах (никакой шаблонизации!) - а оно превращается во вполне себе фронт + бэк на Spring и React, который находится внутри JAR-файла с обычным спринговым томкатом. Достаточно просто ввести mvn package :)


    1. gavrilovegor519
      17.02.2025 14:57

      Лучше Vaadin'а ничего нету :D

      Если что, я этот комментарий писал с некоторым сарказмом (о чём свидетельствует тот смайлик в конце). Идея писать сайт на "взрослом" ЯП конечно хороша, но у Vaadin есть недостаток - он тормозной, и плохо поддаётся автоматическому тестированию, а также не подходит под микросервисы точно.


  1. AntonSurikov
    17.02.2025 14:57

    звучит интересно


  1. semendyaevanton
    17.02.2025 14:57

    сам юзаю продукты от испсистем и ни на что их не променяю, так что будет интересно ознакомиться с дашбордом. ждем-с