Дерево страниц

Сравнение версий

Ключ

  • Эта строка добавлена.
  • Эта строка удалена.
  • Изменено форматирование.

Конфигурация ЛК состоит из трех файлов, расположенных в папке WEB-INF: основного файла конфигурации конфигурации mybgbilling-conf.groovy, файла конфигурации меню меню mybgbilling-menu.groovy, файла конфигурации платежных систем систем mybgbilling-payment.groovy. Файлы конфигурации созданы с использованием синтаксиса Groovy. Значение синтаксиса Groovy.

Scroll Ignore

Оглавление
printablefalse

Описание синтаксиса

Группы параметров в конфиге разделяются не точкой, а с помощью вложенных блоков. Значение параметра должно быть правильным Groovy/Java-объектом - в простом случае строкой, заключенной в одинарные или двойные кавычки, или числом. Группы параметров разделяются не точкой, а с помощью вложенных блоков, например:

Блок кода
languagescala
one {
	two {
		parameterA = 'value1'
		three {
			parameterA = 'value2'
			parameterB = 100
		}
	}
}

Т.е. параметр конфигурации - это один или несколько вложенных блоков, имя параметра и значение после знака =. Данный пример в конфигурации модулей биллинга выглядел бы так:

...

Блок кода
languagescala
example {
    map = [
    	key: 'value',
    	key2:value 200
    ]
}

Также параметры могут быть прописаны как ассоциативный массив, заключенный в круглые скобки (значение в этом случае прописывается через ':' (двеоточие), а не через символ '='):

Блок кода
languagescala
authentication {

    modes = [
    	authenticationMode( mode: 'contract' ), 
    	authenticationMode( mode: 'login', module: 'inet', moduleId: 1 )
     	}
    ]
}

Некоторые значения могут быть динамическими, если использовать замыкания (closure). Т.е., грубо говоря, значением может быть функция, которая будет возвращать нужное значение:

Блок кода
languagescala
status {
			// возможность изменения статуса договора
			//statusChange = { contract -> return contractInGroup( contract, [1, 2, 3, 4, 20] ) && isCustomer(); }
			//statusChange = { contract -> contractInGroup( contract, [1, 2, 3, 4, 20] ) && isCustomer() }
			statusChange = { isCustomer() }
}

В mybgbilling-conf.groovy и mybgbilling-menu.groovy в таких замыканиях можно использовать определенный набор методов, аргумент объект-contract, а также дополнительные аргументы, специфичные для определенного параметра конфигурации (например, параметры content.kernel.customerTitle и content.kernel.subContractGroup):

Блок кода
languagescala
content {
	kernel {
		// название контрагента, отображаемое на странице
		customerTitle = { contract, contractParameterMap ->
		
			// ID параметров договоров названия физ. лиц (для customerTitle)
			def individualCustomerTitleParamIds = [0, 0, 0, 0, 0];
			// ID параметров договоров названия юр. лиц (для customerTitle)
			def corporationCustomerParamIds = [0, 0, 0, 0, 0];
	
			def paramIds = contract.personType == 1 ? corporationCustomerParamIds : individualCustomerTitleParamIds;
	
			String result = contractParameterMap.values().stream()
				.filter{ v -> paramIds.contains( v.entitySpecAttrId ) && notBlankString( v.toString() ) }
				.findFirst()
				.map{ v -> v.toString() }
				.orElse( null );
			
			// можно отобразить и просто комментарий договора
			//if( result == null ) {
			//	result = contract.comment;
			//}
			
			return result;
		}
	}
}

В замыканиях можно использовать методы:

  • isCustomer() или isUserInRole('customer') - возвращает true, если в режиме аутентификации, которым воспользовался абонент, не указан параметр role = 'unauthCustomer';
  • contractInGroup( contract, groupIds ) - возвращает true, если переданный в первый аргумент объект-contract содержит в себе одну из групп, указанных списке второго аргумента, например: contractInGroup( contract, [2, 3, 8, 13] ).

Основная конфигурация (mybgbilling-conf.groovy)

Основная конфигурация личного кабинета состоит из нескольких блоков:

  • bgbilling - конфигурация подключения к BGBillingServer,
  • authentication - параметры аутентификации абонента,
  • mail - параметры почтовой подсистемы (чтобы ЛК мог отправлять письма при необходимости),
  • content - параметры содержимого страниц.

Конфигурация подключения к BGBillingServer

Блок кода
languagescala
// Параметры подключения к BGBillingServer.
// ЛК является пользователем биллинга, общается с ним также, как BGBillingClient
bgbilling {
    // URL доступа к BGBilling
    url = 'http://127.0.0.1:8080/bgbilling/executer'
    // Логин
    user = 'customer'
    // Пароль
    password = '123456'
}

Параметры идентификации HTTP-соединения

Личному кабинету в некоторых случаях требуется знать IP-адрес абонента, который пользуется им в текущий момент (например, для авторизации по IP-адресу или блокировке при переборе логинов/паролей). Поэтому при использовании NGINX требуется указать HTTP-заголовок в параметре context.hostHttpRequestHeader, из которого получать реальный IP-адрес вместо физического IP-адреса HTTP-соединения.

Блок кода
languagescala
context {
	
	...
    
    // Идентификатор хоста по HTTP-заголовку, например, X-Real-IP. По умолчанию используется IP-адрес хоста
    hostHttpRequestHeader = 'X-Real-IP'
}

Параметры аутентификации абонента

Блок кода
languagescala
// Параметры аутентификации абонента
authentication {
    // Кол-во ошибок аутентификации, после которого будет отображаться captcha для этого логина
    captchaLoginErrorCount = 5
    // Кол-во ошибок аутентификации, после которого будет отображаться captcha для хоста
    captchaHostErrorCount = 20
    // Кол-во ошибок аутентификации, после которых будут заблокированы попытки этого хоста
    blockHostErrorCount = 30
    
    // Режимы аутентификации для входа в ЛК
    modes = [
		// аутентификация по номеру договора
    	authenticationMode {
 			mode = 'contract'
    	}
 	]
}

Режимов аутентификации может быть несколько - в этом случае в окне логина можно выбрать необходимый. На данный момент поддерживаются три режима аутентификации:

  • по номеру договора

    Блок кода
    languagescala
    authenticationMode {
    	mode = 'contract'
    }
  • по логину модуля Inet

    Блок кода
    languagescala
    authenticationMode {
    	module = 'inet'
    	mode = 'login'
    	// ID модуля
    	moduleId = 1
    }
  • по IP-адресу сессии модуля Inet (вход без пароля)

    Блок кода
    languagescala
    authenticationMode {
    	module = 'inet'
    	mode = 'ip'
    	// ID модуля
    	moduleId = 1
    	// ограниченный доступ
    	role = 'unauthCustomer'
    }

Для режима аутентификации можно назначить, чтобы доступ после аутентификации через него был ограничен. Для этого указывается параметр role = 'unauthCustomer'. В этом случае, вызов isUserInRole( "customer" ) будет возвращать false. Ограниченный доступ может быть указан, например, для режима аутентификации по IP-адресу модуля Inet.

Можно разрешить аутентификацию для определенных групп договоров, указав условие в параметре filter:

Блок кода
languagescala
authenticationMode {
	module = 'inet'
	mode = 'ip'
	//ID модуля
	moduleId = 1
	// ограниченный доступ
	role = 'unauthCustomer'
    // фильтр по группам договоров
	filter = { contract -> contractInGroup( contract, [1, 2, 3, 4, 20] ) }
}

Или наоборот, запретить для определенных групп договоров:

Блок кода
languagescala
	filter = { contract -> !contractInGroup( contract, [1, 2, 3, 4, 20] ) }

Или разрешить по номеру договора:

Блок кода
languagescala
	filter = { contract -> contract.title.startsWith( "NK" ) }

Или использовать регулярное выражение:

Блок кода
languagescala
	filter = { contract -> contract.title.matches( "NK.*" ) }

Параметры почтовой подсистемы

Блок кода
languagescala
// Параметры SMTP, чтобы ЛК мог отправлять письма
mail {
	smtp {
		host = 'smtp.provider.ru'
	}
	
	from {
		email = 'support@provider.ru'
		name = 'BGBilling'
	}
}

Параметры содержимого страниц

Разрешенные фрагменты

Данный блок конфигурации позволяет настраивать, какие фрагменты страницы или какие действия доступны абонентам или группам абонентов. Например, в коде страницы статусов договора есть фрагмент смены статуса:

Блок кода
languagexml
<ui:fragment rendered="#{configuration.get('content.kernel.status.statusChange', true)}">
	...
</ui:fragment>

Соответственно можно в конфигурации запретить всем менять статус договора из личного кабинета:

Блок кода
languagescala
content {
	kernel {
		...
	
		// status.xhtml
		status {
			// возможность изменения статуса договора
			statusChange = false
		}
		
		...
	}
	
	...
}

Можно разрешить только тем, кто был аутентифицирован по логину/паролю (в конфигурации по умолчанию установлен этот вариант):

Блок кода
languagescala
statusChange = { isUserInRole( "customer" ) }

Разрешить только аутентифицированным по логину/паролю физ. лицам:

Блок кода
languagescala
statusChange = { contract -> isUserInRole( "customer" ) && contract.getPersonType() == 0 }

Или разрешить только аутентифицированным по логину/паролю определенным группам договоров:

Блок кода
languagescala
statusChange = { contract -> isUserInRole( "customer" ) && contractInGroup( contract, [1, 2, 3, 4, 20] ) }

Название контрагента в верхней части страницы

По умолчанию в шапке страницы название или имя контрагента не отображается. За отображение названия (или имени) отвечает параметр content.kernel.customerTitle. В конфигурации можно указать, чтобы отображался комментарий договора:

Блок кода
languagescala
content {
	kernel {
 
	// название контрагента, отображаемое на странице
	customerTitle = { contract, contractParameterMap -> contract.comment }
 
	...
}

Или же отобразить параметр договора, в зависимости от типа лица договора (физ. лицо или юр. лицо):

Блок кода
languagescala
content {
	kernel {

		// название контрагента, отображаемое на странице
		customerTitle = { contract, contractParameterMap ->

			// ID параметров договоров названия физ. лиц (для customerTitle)
			def individualCustomerTitleParamIds = [33, 0, 0, 0, 0];
			// ID параметров договоров названия юр. лиц (для customerTitle)
			def corporationCustomerParamIds = [10, 0, 0, 0, 0];

			def paramIds = contract.personType == 1 ? corporationCustomerParamIds : individualCustomerTitleParamIds;

			String result = contractParameterMap.values().stream()
				.filter{ v -> paramIds.contains( v.entitySpecAttrId ) && notBlankString( v.toString() ) }
				.findFirst()
				.map{ v -> v.toString() }
				.orElse( null );

			return result;
		}
 
		...
	}
	
	...}

Группировка субдоговоров в меню

Если субдоговоров у данного договора меньше 10 - они отображаются прямо в меню. В этом случае можно сортировать и группировать список субдоговоров:

Блок кода
languagescala
content {
	kernel {

		// группировка субдоговоров (для меню)
		subContractGroup = { subContractList ->
		
			subContractList
			.stream()
			.sorted({ a,b -> a.title.compareTo(b.title) })
			.collect( Collectors.groupingBy{ contract ->

				// можно группировать субдоговора по группам договоров
				if( contractInGroup( contract, [1, 2, 3, 4, 20] ) ) {
					return "contract.sub.group.01.internet";
				}else if( contractInGroup( contract, [5, 6, 7, 8, 9] ) ) {
					return "contract.sub.group.02.phone";
				} else {
					return "contract.sub.group.99.other";
				}

				// если всем возвращать пустую строку - то группировки не будет
				return "";
			})
			.entrySet()
			.stream()
			.sorted({ a,b -> a.key.compareTo(b.key) })
			.collect( Collectors.toList() );
		}
 
		...
	}
 
	...}

В примере при группировке используются строки вида "contract.sub.group.01.internet". Число в данном случае используется для сортировки групп, а само название группы должно быть прописано в Locale_ru_RU.properties по ключу:

Блок кода
languagescala
contract.sub.group.01.internet=Интернет
contract.sub.group.02.phone=Телефония
contract.sub.group.99.other=Другое

Конфигурация меню (mybgbilling-menu.groovy)

Данный файл конфигурации возвращает дерево пунктов меню для договора. Выглядит конфигурация, например, так:

Блок кода
languagescala
menu {
	// список пунктов верхнего уровня
	children = [
	
		// Новости
		menu( page: "kernel/news", icon: "fa-newspaper-o", title: "menu.news" ),
		
		// Уведомления + Рассылки
		menu( page: "kernel/notificationsEx", subPage: "notifications", icon: "fa-envelope-o", 
						title: "menu.notifications", badge: "#{notificationBean.getUnreadCount()}", badgeUpdate: "#{notificationBean.populate()}",
						show: isCustomer() ),
	
		// Уведомления (отдельно от рассылок)
		menu( page: "kernel/notifications", icon: "fa-envelope-o", title: "menu.notifications",
						show: !isCustomer() ),
							
		// Баланс
		menu( page: "kernel/balance", icon: "fa-rub", title: "menu.balance" ),
	
		// Лимит
		menu( page: "kernel/limit", icon: "fa-umbrella", title: "menu.limit" ),
		
		// Тарифные опции
		menu( page: "kernel/tariffOptions", icon: "fa-cogs", title: "menu.tariffOptions", show: isCustomer() ),

		// Договор
		menu( icon: "fa-briefcase", title: "menu.contract" ) {
				children = [
					// Статус
					menu( page: "kernel/status", title: "menu.status" ),
					// Тарифы
					menu( page: "kernel/tariffs", title: "menu.tariffs", show: isCustomer() ),
					// Действия
					menu( page: "kernel/additionalActions", title: "menu.additionalActions", show: isCustomer() ),
					// Документы
					menu( page: "kernel/documents", title: "menu.documents", show: isCustomer() ),
					// Документы (включены в предыдущий пункт)
					//menu( page: "plugins/documents/documents", title: "menu.documents" ),
					// Бухгалтерия
					menu( module: "bill", page: "modules/bill/bill", title: "menu.bill", show: isCustomer() ),
					// Примечания
					menu( page: "kernel/notes", title: "menu.notes", show: isCustomer() ),
					// Смена пароля
					menu( page: "kernel/password", title: "menu.password", show: isCustomer() )
				]
			},

		// Интернет
		menu( module:"inet", icon:"fa-globe", title:"menu.inet" ) {
				children = [
					// Сессии
					menu( page: "modules/inet/sessions", title: "menu.inet.sessions" ),
					// Трафик
					menu( page: "modules/inet/traffics", title: "menu.inet.traffics" ),
					// Смена пароля
					menu( page: "modules/inet/password", title: "menu.inet.password", show: isCustomer() )
				]
			},
			
		// ТВ
		menu( module:"tv", page:"modules/tv/tv", icon:"fa-tv", title:"menu.tv" ),
	
		// Поддержка
		menu( page: "plugins/helpdesk/helpdesk", icon: "fa-wrench", title: "menu.helpdesk",
							badge: "#{helpdeskBean.getUnreadTopicCount()}", badgeUpdate: "#{helpdeskBean.populateTopics()}",
							show: isCustomer() )
	
	]
}

У каждого объекта-пункта меню есть набор параметров:

  • module - модуль, если данный пункт относится к модулю, наследуется дочерними пунктами;
  • moduleId - ID модуля (необязательно, если указан module, то подставляется автоматически), наследуется дочерними пунктами. Можно использовать, если одинаковые модули нужно показывать по разному;
  • page - страница, без .xhtml;
  • subPage - подстраница;
  • icon - иконка;
  • title - название пункта меню (ключ для Locale.properties);
  • badge - счетчик, указывается JSF-вызов метода, который вернет число;
  • badgeUpdate - JSF-вызов метода, который нужно произвести для обновления счетчика
  • show - показывать пункт или нет (если не указан, то показывать)
  • children - список дочерних пунктов меню

Используя параметр show, можно ограничивать использование пунктов меню для групп договоров:

Блок кода
languagescala
 menu( moduleId: 210, page: "modules/tv/tv", icon: "fa-tv", title: "menu.tv",
							show: contractInGroup( contract, [1, 2, 3, 4, 20] ) )

При необходимости список дочерних пунктов меню можно определить как переменную и добавлять пункты в этот список, используя условия:

Блок кода
languagescala
 
menu {
	// список пунктов верхнего уровня
	def firstLevel = [];
	children = firstLevel;
	
	// Новости
	firstLevel << menu( page: "kernel/news", icon: "fa-newspaper-o", title: "menu.news" )
	
	// если авторизован по логину/паролю
	if( isCustomer() ) {
	
		// Уведомления + Рассылки
		firstLevel << menu( page: "kernel/notificationsEx", subPage: "notifications", icon: "fa-envelope-o", 
							title: "menu.notifications", badge: "#{notificationBean.getUnreadCount()}", badgeUpdate: "#{notificationBean.populate()}" )
	
	} else {
	
		// Уведомления
		firstLevel << menu( page: "kernel/notifications", subPage: "", icon: "fa-envelope-o", title: "menu.notifications" )
	
	}
	// Баланс
	firstLevel << menu( page: "kernel/balance", icon: "fa-rub", title: "menu.balance" )
	
	// если авторизован по логину/паролю
	if( isCustomer() ) {
	
		// Лимит
		firstLevel << menu( page: "kernel/limit", icon: "fa-umbrella", title: "menu.limit" )
		
		// Тарифные опции
		firstLevel << menu( page: "kernel/tariffOptions", icon: "fa-cogs", title: "menu.tariffOptions" )
 
...