Month: November 2024
Sharepoint conditional formatting not applying to item view
Hello,
I require some help with a sharepoint list that I have setup to track issues. I have a column that has a priority label: Low, Medium or High based on a number value.
I have setup a conditional formatting see below in list view:
However, this conditional formatting does not show in the item view see below:
Is anyone able to tell me why and how do i correct this?
Many thanks
Hello,I require some help with a sharepoint list that I have setup to track issues. I have a column that has a priority label: Low, Medium or High based on a number value. I have setup a conditional formatting see below in list view: However, this conditional formatting does not show in the item view see below: Is anyone able to tell me why and how do i correct this? Many thanks Read More
suggestion: link a ToDo with a calendar event
Hi,
I wondered if this was an option, if not, I wanted to suggest it should be added.
So I have an event which I will have many instance in my calendar which is an appointment to go see a specific health specialist I see at least 3 times a week. Time changes and everything.
I have a ToDo associated that I repeat each time I have this event. I would like to be able to add into each of those appointment in calendar, a link to the ToDo to access it quickly. Is there a way to do it? If not, is it something that could be implemented?
Thanks in advance!!
Hi, I wondered if this was an option, if not, I wanted to suggest it should be added. So I have an event which I will have many instance in my calendar which is an appointment to go see a specific health specialist I see at least 3 times a week. Time changes and everything. I have a ToDo associated that I repeat each time I have this event. I would like to be able to add into each of those appointment in calendar, a link to the ToDo to access it quickly. Is there a way to do it? If not, is it something that could be implemented? Thanks in advance!! Read More
Old bug when switching between calendar and mail
Simple bug that have been happening for years and is still not solved.
In my outlook I often switch to calendar and email. Sometime, after messing with calendar by toggling views in calendar, for some reason, my outlook email pan switch view from Compact to Preview? Why?
This has been occurring for at least 6 years, with other emails / computers, also to colleagues.
Simple bug that have been happening for years and is still not solved. In my outlook I often switch to calendar and email. Sometime, after messing with calendar by toggling views in calendar, for some reason, my outlook email pan switch view from Compact to Preview? Why? This has been occurring for at least 6 years, with other emails / computers, also to colleagues. Read More
Restricted Planner View based on Filters
Hi everyone,
I have a main Planner plan where all tasks are visible. However, I don’t want all employees to see every task—each employee should only see tasks with a specific label assigned to them. My goal is to create a filtered version of the main plan that only shows tasks with certain labels, allowing employees to view their tasks in a separate, filtered plan.
This filtered plan should serve solely as a status overview, meaning no changes are made here; it simply reflects the main plan. If a task is moved between buckets in the main plan, I want this change to be mirrored automatically in the filtered plan.
Has anyone else managed to sync Planner tasks between plans or buckets? Any tips on setting up a more efficient flow, or suggestions for workarounds, would be really appreciated. Thank you!
Hi everyone,I have a main Planner plan where all tasks are visible. However, I don’t want all employees to see every task—each employee should only see tasks with a specific label assigned to them. My goal is to create a filtered version of the main plan that only shows tasks with certain labels, allowing employees to view their tasks in a separate, filtered plan.This filtered plan should serve solely as a status overview, meaning no changes are made here; it simply reflects the main plan. If a task is moved between buckets in the main plan, I want this change to be mirrored automatically in the filtered plan.Has anyone else managed to sync Planner tasks between plans or buckets? Any tips on setting up a more efficient flow, or suggestions for workarounds, would be really appreciated. Thank you! Read More
Cannot switch email from ToDo?
Hi,
I have work email and my personal email on my Outlook (Windows computer). When in ToDo, I cannot switch email, I have to go in calendar and select only the calendar I want to pick the ToDo I want. On phone, I can switch email in ToDo that is used.
On Windows Outlook, I couldn’t find this option after a long time. Does it exist? I have to go through calendar every time.
Hi, I have work email and my personal email on my Outlook (Windows computer). When in ToDo, I cannot switch email, I have to go in calendar and select only the calendar I want to pick the ToDo I want. On phone, I can switch email in ToDo that is used. On Windows Outlook, I couldn’t find this option after a long time. Does it exist? I have to go through calendar every time. Read More
suggestion: allow step to have more details
I wanted to suggest adding to each steps, more descriptions or even better, steps could contains sub step. Similar to point form where you can add infinite subpoints, this would be useful the same way it is to have many levels in a point form.
Or is there already a way to do so? I’m still new with this.
I wanted to suggest adding to each steps, more descriptions or even better, steps could contains sub step. Similar to point form where you can add infinite subpoints, this would be useful the same way it is to have many levels in a point form. Or is there already a way to do so? I’m still new with this. Read More
Does Microsoft a way of searching an organization’s code for Windows Enterprise organization?
Has there ever been a Microsoft product that allows one to search by code syntax (in internal cloud) of certain specific extension files–like Gitlab or Bitbucket can do?
At my organization, the Sharepoint and even the Azure’s Microsoft graph is moving toward “””Content””” and AI-based search. During this transition, I have found its often harder and harder to find certain files and emails in my organization based on symbols that document might contain.
These are examples of symbols that are really important to my business…
%m+% # perhaps the most important symbol to the accounting and finance
%w+% # the biweekly version of the same symbol
%>%
|>
Its come to the point, that I have a local OneDrive copy where thousands 1000 kb or less (1.2 Gb of storage space) file are saved just so I can use more simplistic search methods over these files. But I feel like its such a waste…. if there was a better method.
So I was curious if anyone at Microsoft has ever come up with a cloud based solution to the code search and exact search problem that has become worse as a result of reliance on OpenAI
Has there ever been a Microsoft product that allows one to search by code syntax (in internal cloud) of certain specific extension files–like Gitlab or Bitbucket can do? At my organization, the Sharepoint and even the Azure’s Microsoft graph is moving toward “””Content””” and AI-based search. During this transition, I have found its often harder and harder to find certain files and emails in my organization based on symbols that document might contain.These are examples of symbols that are really important to my business…%m+% # perhaps the most important symbol to the accounting and finance%w+% # the biweekly version of the same symbol%>%|> Its come to the point, that I have a local OneDrive copy where thousands 1000 kb or less (1.2 Gb of storage space) file are saved just so I can use more simplistic search methods over these files. But I feel like its such a waste…. if there was a better method. So I was curious if anyone at Microsoft has ever come up with a cloud based solution to the code search and exact search problem that has become worse as a result of reliance on OpenAI Read More
Problem to change site url’s in SharePoint admin center
Since a short time ago, I cannot change the url for some sites. I know that sites that are hub-sites, or connected to a hub, can not be changed unless the are released from the hub. It only seems to affect sites linked to a 365 group.
I get almost the standard message, when trying to change url, but with the exception of this text:
“Some features may not work after you change this location address. Do you want to continue? The site has a Business Connectivity Services (BCS) connection. The connection may need to be re-established after you change the location address.”
Anyone having the same problem or know how I can fix this?
/Hans
Since a short time ago, I cannot change the url for some sites. I know that sites that are hub-sites, or connected to a hub, can not be changed unless the are released from the hub. It only seems to affect sites linked to a 365 group. I get almost the standard message, when trying to change url, but with the exception of this text:”Some features may not work after you change this location address. Do you want to continue? The site has a Business Connectivity Services (BCS) connection. The connection may need to be re-established after you change the location address.” Anyone having the same problem or know how I can fix this?/Hans Read More
99贵宾厅开户-17300435119
实现 Microsoft 365 各种功能和应用的开发工作。他们运用不同的编程语言和技术,不断优化和改进产品的性能与功能,以满足用户的需求。例如,在开发新的办公软件功能时,开发工程师需要确保功能的稳定性和兼容性。 Read More
万宝路公司开户-17300435119
Excel 的公式审核功能可以算是一种帮助你检查和理解公式运算过程的 “助手”。当你使用复杂的公式时,通过公式审核中的追踪引用单元格、追踪从属单元格等功能,可以清晰地看到公式所涉及的数据来源和影响范围,就像有个 “副驾驶” 在旁边帮你分析公式的逻辑。 Read More
MDE Onboarding issue – 2012 R2 – CheckPPL Error
Hello,
I am facing an onboarding issue with one specific 2012 R2 server. I’ve already ran MDEAnalyzer and there’s an error message: “112004 CheckPPL Please note the sensor on this device is not PPL protected: SERVICE sense PROTECTION LEVEL: NONE.. “. Event viewer logs for Sense service contains multiple warning events ID 65 “Failed to load Microsoft Security Events Component Minifilter driver. Failure code: 0x80070005”. Server’s status in MDE is “can be onboarded”.
Any suggestions will be highly appreciated!
Hello, I am facing an onboarding issue with one specific 2012 R2 server. I’ve already ran MDEAnalyzer and there’s an error message: “112004 CheckPPL Please note the sensor on this device is not PPL protected: SERVICE sense PROTECTION LEVEL: NONE.. “. Event viewer logs for Sense service contains multiple warning events ID 65 “Failed to load Microsoft Security Events Component Minifilter driver. Failure code: 0x80070005”. Server’s status in MDE is “can be onboarded”. Any suggestions will be highly appreciated! Read More
Raspberry Pi & Intune
Hi All,
A bit of a random question which I believe the answer to be no.
Can Intune managed Raspberry Pi devices?
Thought I would double check on here.
Have a good one.
Thanks
Hi All, A bit of a random question which I believe the answer to be no. Can Intune managed Raspberry Pi devices? Thought I would double check on here. Have a good one. Thanks Read More
Site content stuck in classic
I accidentally clicked return to classic sharepoint and cannot get it to go back, the site contents are arranged as thumbnails now instead of a list, it looks awful and is barely useable. There are no settings to restore this and the option to “Return to modern experience” is not there.
Please can someone assist.
I accidentally clicked return to classic sharepoint and cannot get it to go back, the site contents are arranged as thumbnails now instead of a list, it looks awful and is barely useable. There are no settings to restore this and the option to “Return to modern experience” is not there. Please can someone assist. Read More
Quick question
How can I lock data to copy from same row but different columns?
How can I lock data to copy from same row but different columns? Read More
Different (conditional) background colors in a list – Microsoft List vs. Sharepoint Group
Hi,
I have created a Microsoft List that uses conditional row formatting to mark entries that have been changed within the last 31 days with a light blue background color.
This is the JSON for it:
{
“$schema”: “https://developer.microsoft.com/json-schemas/sp/v2/row-formatting.schema.json”,
“additionalRowClass”: {
“operator”: “:”,
“operands”: [
{
“operator”: “<“,
“operands”: [
“[$Age]”,
31
]
},
“sp-css-backgroundColor-BgLightBlue sp-field-fontSizeSmall sp-css-color-BlackText”,
“”
]
}
}
This works fine, as long as I view the list from within Microsoft Lists.
I have also added the List to our SharePoint Group Site, but the the background color here does not look the same. Instead, it is much darker and seemingly the “palette” of usable colors is much smaller.
I tested some other nuances by changing the ‘sp-css-backgroundColor’ to BgGold, BgLightBlue20 and BgLightGrey but always ended up with a much darker background color when displaying the List from the Sharepoint Group.
Does anyone know if there is some parameter in the Sharepoint Group settings that I can change to make the Group display the colors correctly, or any other way to solve this?
Thanks.
Best regards
Patrick
List View from within Microsoft Lists:
List View when embedded in Sharepoint Group:
Hi,I have created a Microsoft List that uses conditional row formatting to mark entries that have been changed within the last 31 days with a light blue background color.This is the JSON for it:{
“$schema”: “https://developer.microsoft.com/json-schemas/sp/v2/row-formatting.schema.json”,
“additionalRowClass”: {
“operator”: “:”,
“operands”: [
{
“operator”: “<“,
“operands”: [
“[$Age]”,
31
]
},
“sp-css-backgroundColor-BgLightBlue sp-field-fontSizeSmall sp-css-color-BlackText”,
“”
]
}
} This works fine, as long as I view the list from within Microsoft Lists. I have also added the List to our SharePoint Group Site, but the the background color here does not look the same. Instead, it is much darker and seemingly the “palette” of usable colors is much smaller.I tested some other nuances by changing the ‘sp-css-backgroundColor’ to BgGold, BgLightBlue20 and BgLightGrey but always ended up with a much darker background color when displaying the List from the Sharepoint Group. Does anyone know if there is some parameter in the Sharepoint Group settings that I can change to make the Group display the colors correctly, or any other way to solve this?Thanks. Best regardsPatrick List View from within Microsoft Lists: List View when embedded in Sharepoint Group: Read More
removable media
Is it possible to block specific file types on removable media using Microsoft Defender for Endpoint?
Is it possible to block specific file types on removable media using Microsoft Defender for Endpoint? Read More
Modernising Registrar Technology: Implementing EPP with Kotlin, Spring & Azure Container Apps
Introduction
In the domain management industry, technological advancement has often been a slow and cautious process, lagging behind the rapid innovations seen in other tech sectors. This measured pace is understandable given the critical role domain infrastructure plays in the global internet ecosystem. However, as we stand on the cusp of a new era in web technology, it is becoming increasingly clear that modernization should be a priority. This blog post embarks on a journey to demystify one of the most critical yet often misunderstood components of the industry: the Extensible Provisioning Protocol (EPP).
Throughout this blog, we will dive deep into the intricacies of EPP, exploring its structure, commands and how it fits into the broader domain management system. We will walk through the process of building a robust EPP client using Kotlin and Spring Boot. Then, we will take our solutions to the next level by containerizing with Docker and deploying it to Azure Container Apps, showcasing how modern cloud technologies can improve the reliability and scalability of your domain management system. We will also set up a continuous integration and deployment (CI/CD) pipeline, ensuring that your EPP implementation remains up-to-date and easily maintainable.
By the end of this blog, you will be able to provision domains programatically via an endpoint, and have the code foundation ready to create dozens of other domain management commands (e.g. updating nameservers, updating contact info, renewing and transferring domains).
Who it is for
What you will need: EPP credentials
Understanding EPP
EPP is short for Extensible Provisioning Protocol. It is a protocol designed to streamline and standardise communication between domain name registries and registrars. Developed to replace older, less efficient protocols, EPP has become the industry standard for domain registration and management operations.
Stateful connections: EPP maintains persistent connections between registrars and registries, reducing overhead and improving performance.
Extensibility: As the name suggests, EPP is designed to be extensible. Registries can add custom extensions to support unique features or requirements.
Standardization: EPP provides a uniform interface across different registries, simplifying integration for registrars and reducing development costs.
Kotlin
Spring
Azure Container Apps (‘ACA’)
The architecture
Registrant (end user) requests to purchase a domain
Website backend sends instruction to EPP API (what we are making in this blog)
EPP API sends command to the EPP server provided by the registry
Response provided by registry and received by registrant (end user) on website
Setting up the development environment
Prerequisites
For this blog, I will be using the following technologies:
Visual Studio Code (VS Code) as the IDE (integrated development environment). I will be installing some extensions and changing some settings to make it work for our technology. Download at Download Visual Studio Code – Mac, Linux, Windows
Docker CLI for containerization and local testing. Download at Get Started | Docker
Azure CLI for deployment to Azure Container Registry & Azure Container Apps (you can use the portal if more comfortable). Download at How to install the Azure CLI | Microsoft Learn
Git for version control and pushing to GitHub to setup CI/CD pipeline. Download at Git – Downloads (git-scm.com)
VS Code Extensions
Kotlin
Spring Initialzr Java Support
Implementing EPP with Kotlin & Spring
Creating the project
First up, let us create a blank Spring project. We will do this with the Spring Initializr plugin we just installed:
Press CTRL + SHIFT + P to open the command palette
Select Spring Initialzr: Create a Gradle project…
Select version (I recommend 3.3.4)
Select Kotlin as project language
Type Group Id (I am using com.stephen)
Type Artifact ID (I am using eppapi)
Select jar as packaging type
Select any Java version (The version choice is yours)
Add Spring Web as a dependency
Choose a folder
Open project
Your project should look like this:
We are using the Gradle build tool for this project. Gradle is a powerful, flexible build automation tool that supports multi-language development and offers convenient integration with both Kotlin & Spring. Gradle will handle our dependency management, allowing us to focus on our EPP implementation rather than build configuration intricacies.
Adding the EPP dependency
It handles the low-level details of EPP communication, allowing us to focus on business logic.
It is a Java-based implementation, which integrates seamlessly with our Kotlin and Spring setup.
It supports all basic EPP commands out of the box, such as domain checks, registrations and transfers.
Modifying the build settings
toolchain {
languageVersion = JavaLanguageVersion.of(21)
}
sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_21
}
kotlin {
jvmToolchain(21)
}
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile) {
kotlinOptions {
jvmTarget = “21”
freeCompilerArgs = [“-Xjsr305=strict”]
}
}
tasks.named(‘test’) {
enabled = false
}
The structure
Rename the main class to EPPAPI.kt (Spring auto generation did not do it justice).
Split the code into two folders: epp and api, with our main class remaining at the root.
Create a class inside the epp folder named EPP.kt – this is where we will connect to and manage the EPPClient soon.
Create a class inside the api folder named API.kt – this is where we will configure and run the Spring API.
api
└── API.kt
epp
└── EPP.kt
PORT=700
USERNAME=X
PASSWORD=X
The code
import java.net.Socket
import java.security.KeyStore
import java.security.cert.X509Certificate
import javax.net.ssl.KeyManagerFactory
import javax.net.ssl.SSLContext
import javax.net.ssl.TrustManager
import javax.net.ssl.X509TrustManager
class EPP private constructor(
host: String,
port: Int,
username: String,
password: String,
) : EPPClient(host, port, username, password) {
companion object {
private val HOST = System.getenv(“HOST”)
private val PORT = System.getenv(“PORT”).toInt()
private val USERNAME = System.getenv(“USERNAME”)
private val PASSWORD = System.getenv(“PASSWORD”)
lateinit var client: EPP
fun create(): EPP {
println(“Creating client with HOST: $HOST, PORT: $PORT, USERNAME: $USERNAME”)
return EPP(HOST, PORT, USERNAME, PASSWORD).apply {
try {
println(“Creating SSL socket…”)
val socket = createSSLSocket()
println(“SSL socket created. Setting socket to EPP server…”)
setSocketToEPPServer(socket)
println(“Socket set. Getting greeting…”)
val greeting = greeting
println(“Greeting received: $greeting”)
println(“Connecting…”)
connect()
println(“Connected. Logging in…”)
login(PASSWORD)
println(“Login successful.”)
client = this
} catch (e: Exception) {
println(“Error during client creation: ${e.message}”)
e.printStackTrace()
throw e
}
}
}
private fun createSSLSocket(): Socket {
val sslContext = setupSSLContext()
return sslContext.socketFactory.createSocket(HOST, PORT) as Socket
}
private fun setupSSLContext(): SSLContext {
val trustAllCerts = arrayOf<TrustManager>(object : X509TrustManager {
override fun getAcceptedIssuers(): Array<X509Certificate>? = null
override fun checkClientTrusted(certs: Array<X509Certificate>, authType: String) {}
override fun checkServerTrusted(certs: Array<X509Certificate>, authType: String) {}
})
val keyStore = KeyStore.getInstance(KeyStore.getDefaultType()).apply {
load(null, null)
}
val kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()).apply {
init(keyStore, “”.toCharArray())
}
return SSLContext.getInstance(“TLS”).apply {
init(kmf.keyManagers, trustAllCerts, java.security.SecureRandom())
}
}
}
}
EPP.create()
}
Domains: These are the web addresses that users type into their browsers. In EPP, a domain object represents the registration of a domain name.
Contacts: These are individuals or entities associated with a domain. There are typically four types of contact: Registrant, Admin, Tech & Billing. ICANN (Internet Corporation for Assigned Names and Numbers) mandates that every provisioned domain must have a valid contact attached to it.
Hosts: Also known as nameservers, these are the servers that translate domain names into IP addresses. In EPP, host objects can either be internal (subordinate to a domain in the registry) or external.
api
└── API.kt
epp
├── contact
├── domain
│ └── CheckDomain.kt
├── host
└── EPP.kt
import epp.EPP
import com.tucows.oxrs.epprtk.rtk.xml.EPPDomainCheck
import org.openrtk.idl.epprtk.domain.epp_DomainCheckReq
import org.openrtk.idl.epprtk.domain.epp_DomainCheckRsp
import org.openrtk.idl.epprtk.epp_Command
fun EPP.Companion.checkDomain(
domainName: String,
): Boolean {
val check = EPPDomainCheck().apply {
setRequestData(
epp_DomainCheckReq(
epp_Command(),
arrayOf(domainName)
)
)
}
val response = processAction(check) as EPPDomainCheck
val domainCheck = response.responseData as epp_DomainCheckRsp
return domainCheck.results[0].avail
}
We create an EPPDomainCheck object, which represents an EPP domain check command.
We set the request data using epp_DomainCheckReq. This takes an epp_command (a generic EPP command) and an array of domain names to check. In this case, we are only checking one domain.
We process the action using our EPP client’s processAction function, which sends the request to the EPP server.
We cast the response to EPPDomainCheck and extract the responseData.
Finally, we return whether the domain is available or not from the first (and only result) by checking the avail value.
EPP.create()
println(EPP.checkDomain(“example.gg”))
}
import epp.EPP
import org.openrtk.idl.epprtk.contact.*
import org.openrtk.idl.epprtk.epp_AuthInfo
import org.openrtk.idl.epprtk.epp_AuthInfoType
import org.openrtk.idl.epprtk.epp_Command
fun EPP.Companion.createContact(
contactId: String,
name: String,
organization: String? = null,
street: String,
street2: String? = null,
street3: String? = null,
city: String,
state: String? = null,
zip: String? = null,
country: String,
phone: String,
fax: String? = null,
email: String
): Boolean {
val create = EPPContactCreate().apply {
setRequestData(
epp_ContactCreateReq(
epp_Command(),
contactId,
arrayOf(
epp_ContactNameAddress(
epp_ContactPostalInfoType.INT,
name,
organization,
epp_ContactAddress(street, street2, street3, city, state, zip, country)
)
),
phone.let { epp_ContactPhone(null, it) },
fax?.let { epp_ContactPhone(null, it) },
email,
epp_AuthInfo(epp_AuthInfoType.PW, null, “pass”)
)
)
}
val response = client.processAction(create) as EPPContactCreate
val contactCreate = response.responseData as epp_ContactCreateRsp
return contactCreate.rsp.results[0].m_code.toInt() == 1000
}
import epp.EPP
import org.openrtk.idl.epprtk.epp_Command
import org.openrtk.idl.epprtk.host.epp_HostAddress
import org.openrtk.idl.epprtk.host.epp_HostAddressType
import org.openrtk.idl.epprtk.host.epp_HostCreateReq
import org.openrtk.idl.epprtk.host.epp_HostCreateRsp
fun EPP.Companion.createHost(
hostName: String,
ipAddresses: Array<String>?
): Boolean {
val create = EPPHostCreate().apply {
setRequestData(
epp_HostCreateReq(
epp_Command(),
hostName,
ipAddresses?.map { epp_HostAddress(epp_HostAddressType.IPV4, it) }?.toTypedArray()
)
)
}
val response = client.processAction(create) as EPPHostCreate
val hostCreate = response.responseData as epp_HostCreateRsp
return hostCreate.rsp.results[0].code.toInt() == 1000
}
import com.tucows.oxrs.epprtk.rtk.xml.EPPDomainCreate
import org.openrtk.idl.epprtk.domain.*
import org.openrtk.idl.epprtk.epp_AuthInfo
import org.openrtk.idl.epprtk.epp_AuthInfoType
import org.openrtk.idl.epprtk.epp_Command
fun EPP.Companion.createDomain(
domainName: String,
registrantId: String,
adminContactId: String,
techContactId: String,
billingContactId: String,
nameservers: Array<String>,
password: String,
period: Short = 1
): Boolean {
val create = EPPDomainCreate().apply {
setRequestData(
epp_DomainCreateReq(
epp_Command(),
domainName,
epp_DomainPeriod(epp_DomainPeriodUnitType.YEAR, period),
nameservers,
registrantId,
arrayOf(
epp_DomainContact(epp_DomainContactType.ADMIN, adminContactId),
epp_DomainContact(epp_DomainContactType.TECH, techContactId),
epp_DomainContact(epp_DomainContactType.BILLING, billingContactId)
),
epp_AuthInfo(epp_AuthInfoType.PW, null, password)
)
)
}
val response = client.processAction(create) as EPPDomainCreate
val domainCreate = response.responseData as epp_DomainCreateRsp
return domainCreate.rsp.results[0].code.toInt() == 1000
}
import epp.contact.createContact
import epp.domain.createDomain
fun main() {
EPP.create()
val contactResponse = EPP.createContact(
contactId = “12345”,
name = “Stephen”,
organization = “Test”,
street = “Test Street”,
street2 = “Test Street 2”,
street3 = “Test Street 3”,
city = “Test City”,
state = “Test State”,
zip = “Test Zip”,
country = “GB”,
phone = “1234567890”,
fax = “1234567890”,
email = “test@gg.com”
)
if (contactResponse) {
println(“Contact created”)
} else {
println(“Contact creation failed”)
return
}
val domainResponse = EPP.createDomain(
domainName = “randomavailabletestdomain.gg”,
registrantId = “123”,
adminContactId = “123”,
techContactId = “123”,
billingContactId = “123”,
nameservers = arrayOf(“ernest.ns.cloudflare.com”, “adaline.ns.cloudflare.com”),
password = “XYZXYZ”,
period = 1
)
if (domainResponse) {
println(“Domain created”)
} else {
println(“Domain creation failed”)
}
}
Domain created
org.openrtk.idl.epprtk.domain.epp_DomainCreateRsp: { m_rsp [org.openrtk.idl.epprtk.epp_Response: { m_results [[org.openrtk.idl.epprtk.epp_Result: { m_code [1000] m_values [null] m_ext_values [null] m_msg [Command completed successfully] m_lang [] }]] m_message_queue [org.openrtk.idl.epprtk.epp_MessageQueue: { m_count [4] m_queue_date [null] m_msg [null] m_id [916211] }] m_extension_strings [null] m_trans_id [org.openrtk.idl.epprtk.epp_TransID: { m_client_trid [null] m_server_trid [1728110331467] }] }] m_name [randomavailabletestdomain2.gg] m_creation_date [2024-10-05T06:38:51.464Z] m_expiration_date [2025-10-05T06:38:51.493Z] }
Both of those objects were created using our extension functions on top of the EPP-RTK which is in contact with my target EPP server. If your registry has a user interface, you should see that these objects have now been created and are usable going forward. For example, one contact can be used for multiple domains. For my case study, you can see that both objects were successfully created on the Channel Isles side through our EPP communication:
Domain check
Domain info
Domain create
Domain update
Domain delete
Domain transfer
Contact check
Contact info
Contact create
Contact update
Contact delete
Contact transfer
Host check
Host info
Host create
Host update
Host delete
api
├── controller
│ └── ContactController.kt
│ └── DomainController.kt
│ └── HostController.kt
└── API.kt
epp
├── contact
├── domain
│ └── CheckDomain.kt
├── host
└── EPP.kt
The job of controllers in Spring is to handle incoming HTTP requests, process them and return appropriate responses. In the context of our EPP API, controllers will act as the bridge between the client interface and our EPP functionality. Therefore, it makes logical sense to split up the three major sections into multiple classes so that the code does not become unmaintainable.
import epp.domain.checkDomain
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.bind.annotation.RestController
@RestController
class DomainController {
@GetMapping(“/domain-check”)
fun helloWorld(@RequestParam name: String): ResponseEntity<Map<String, Any>> {
val check = EPP.checkDomain(name)
return ResponseEntity.ok(
mapOf(
“available” to check
)
)
}
}
GetMapping(“domain-check”): This annotation maps the HTTP GETrequests to the domain-check route. When a GET request is made to this URL, Spring will call this function to handle it.
fun helloWorld(@RequestParam name: String): This is the function that will handle the request. The @RequestParam annotation tells Spring to extract the name parameter from the query string of the URL. For example, a request to /domain-check?=name=example.gg would set name to example.gg. This allows us to then process the EPP command with their requested domain name.
ResponseEntity<Map<String, Any>>: This is the return type of the function. ResponseEntity allows us to have full control over the HTTP response, including status code, headers and body.
val check = EPP.checkDomain(name): This line calls our EPP function to check if the domain is available (remember, it returns true if available and false if not).
return ResponseEntity.ok(mapOf(“available” to check)): This creates a response with HTTP status 200 (OK) and a body containing the JSON object with a single key available whose value is the result of the domain check.
import org.springframework.boot.runApplication
@SpringBootApplication
class API {
companion object {
fun start() {
runApplication<API>()
}
}
}
import epp.EPP
fun main() {
EPP.create()
API.start()
}
Creating SSL socket…
SSL socket created. Setting socket to EPP server…
Socket set. Getting greeting…
Greeting received: org.openrtk.idl.epprtk.epp_Greeting: { m_server_id [OTE] m_server_date [2024-10-06T05:47:08.628Z] m_svc_menu [org.openrtk.idl.epprtk.epp_ServiceMenu: { m_versions [[1.0]] m_langs [[en]] m_services [[urn:ietf:params:xml:ns:contact-1.0, urn:ietf:params:xml:ns:domain-1.0, urn:ietf:params:xml:ns:host-1.0]] m_extensions [[urn:ietf:params:xml:ns:rgp-1.0, urn:ietf:params:xml:ns:auxcontact-0.1, urn:ietf:params:xml:ns:secDNS-1.1, urn:ietf:params:xml:ns:epp:fee-1.0]] }] m_dcp [org.openrtk.idl.epprtk.epp_DataCollectionPolicy: { m_access [all] m_statements [[org.openrtk.idl.epprtk.epp_dcpStatement: { m_purposes [[admin, prov]] m_recipients [[org.openrtk.idl.epprtk.epp_dcpRecipient: { m_type [ours] m_rec_desc [null] }, org.openrtk.idl.epprtk.epp_dcpRecipient: { m_type [public] m_rec_desc [null] }]] m_retention [stated] }]] m_expiry [null] }] }
Connecting…
Connected. Logging in…
Login successful.
. ____ _ __ _ _
/\ / ___’_ __ _ _(_)_ __ __ _
( ( )___ | ‘_ | ‘_| | ‘_ / _` |
\/ ___)| |_)| | | | | || (_| | ) ) ) )
‘ |____| .__|_| |_|_| |___, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.7.18)
2024-10-06 06:47:09.531 INFO 43872 — [ main] com.stephen.eppapi.EPPAPIKt : Starting EPPAPIKt using Java 1.8.0_382 on STEPHEN with PID 43872 (D:IntelliJ Projectsepp-apibuildclasseskotlinmain started by [Redacted] in D:IntelliJ Projectsepp-api)
2024-10-06 06:47:09.534 INFO 43872 — [ main] com.stephen.eppapi.EPPAPIKt : No active profile set, falling back to 1 default profile: “default”
2024-10-06 06:47:10.403 INFO 43872 — [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2024-10-06 06:47:10.414 INFO 43872 — [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2024-10-06 06:47:10.414 INFO 43872 — [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.83]
2024-10-06 06:47:10.511 INFO 43872 — [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2024-10-06 06:47:10.511 INFO 43872 — [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 928 ms
2024-10-06 06:47:11.220 INFO 43872 — [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ”
2024-10-06 06:47:11.229 INFO 43872 — [ main] com.stephen.eppapi.EPPAPIKt : Started EPPAPIKt in 2.087 seconds (JVM running for 3.574)
/domain-check?name=test.gg – {“available”:false}
/domain-check?name=thisshouldprobablybeavailable.gg – {“available”:true}
Deploying to Azure Container Apps
Now that we have our EPP API functioning locally, it is time to think about productionizing our application. Our goal is to run the API as an Azure Container App (ACA), which is a fully managed environment perfect for easy deployment and scaling of our Spring application. However, before deploying to ACA, we will need to containerise our application. This is where Azure Container Registry (ACR) comes into play. ACR will serve as the private Docker registry to store and manage our container images. It provides a centralised repository for our Docker images and integrates seamlessly with ACA, streamlining our CI/CD pipeline.
FROM openjdk:21-jdk-alpine
# Set the working directory in the container
WORKDIR /app
# Copy the JAR file into the container
COPY build/libs/*.jar app.jar
# Expose the port your application runs on
EXPOSE 8080
# Command to run the application
CMD [“java”, “-jar”, “app.jar”]
./gradlew build – build our application and package into a JAR file found under /build/libs/X.jar.
docker build -t epp-api . – tells Docker to create an image named epp-api based on the instructions in our Dockerfile.
docker run -p 8080:8080 –env-file .env epp-api – start a container from the image, mapping port 8080 of the container to port 8080 on the host machine. We use this port because this is the default port on which Spring exposes endpoints. The -p flag ensures that the application can be accessed through localhost:8080 on your machine. We also specify the .env file we created earlier so that Docker is aware of our EPP login details.
az login – if not already authenticated, be sure to log in through the CLI.
az group create –name registrar –location uksouth – create a resource group if you have not already. I have named mine registrar and chosen the location as uksouth because that is closest to me.
az acr create –resource-group registrar –name registrarcontainers —sku Basic – create an Azure Container Registry resource within our registrar resource group, with the name of registrarcontainers (note that this has to be globally unique) and SKU Basic.
az acr login –name registrarcontainers – login to the Azure Container Registry.
docker tag epp-api myacr.azurecr.io/epp-api:v1 – tag the local Docker image with the ACR login server name.
docker push myacr.azurecr.io/epp-api:v1 – push the image to the container registry!
2111bc7193f6: Pushed
1b04c1ea1955: Pushed
ceaf9e1ebef5: Pushed
9b9b7f3d56a0: Pushed
f1b5933fe4b5: Pushed
v1: digest: sha256:07eba5b555f78502121691b10cd09365be927eff7b2e9db1eb75c072d4bd75d6 size: 1365
az containerapp env create –resource-group registrar –name containers –-location uksouth – create the Container App environment within our resource group with name containers and location uksouth.
az acr update -n registrarcontainers –admin-enabled true – ensure ACR allows admin access.
az containerapp create
–name epp-api
–resource-group registrar
–environment containers
–image registrarcontainers.azurecr.io/epp-api:v1
–target-port 8080
–ingress external
–registry-server registrarcontainers.azurecr.io
–env-vars “HOST=your_host” “PORT=your_port” “USERNAME=your_username” “PASSWORD=your_password”
– creates a new Container App named epp-api within our resource group and the containers environment. It uses the Docker image stored in the ACR. The application inside the container is configured to listen on port 8080 which is where our Spring endpoints will be accessible. The -ingress external flag makes it accessible from the internet. You must also set your environment variables or the app will crash.
Setting up GitHub CI/CD
git init – Initialise a new Git repository in your current directory. This creates a hidden .git directory that stores the repository’s metadata.
git add . – Stages all of the files in the current directory and its subdirectories for commit. This means that these files will be included in the next commit.
git commit -m “Initial commit” – Creates a new commit with the staged files and a common initial commit message.
git remote add origin <URL> – Adds a remote repository named origin to your local repository, connecting it to our remote Git repository hosted on GitHub.
git push origin master – Uploads the local repository’s content to the remote repository named origin, specifically to the master branch.
Head to your Container App
On the sidebar, hit Settings
Hit Deployment
You should find yourself in the Continuous deployment section. There are two headings, let us start with GitHub settings:
Authenticate into GitHub and provide permissions to repository (if published to a GH organization, give permissions also)
Select organization, or your GitHub name if published on personal account
Select the repository you just created (for me, epp-api)
Select the main branch (likely either master or main)
Then, under Registry settings:
Ensure Azure Container Registry is selected for Repository source
Select the Container Registry you created earlier (for me, registrarcontainers)
Select the image you created earlier (for me, epp-api)
It should look something like this:
run: chmod +x gradlew
– name: Set up JDK 21
uses: actions/setup-java@v2
with:
java-version: ’21’
distribution: ‘adopt’
– name: Build with Gradle
run: ./gradlew build
Grant execute permission to gradlew – gradlew is a wrapper script that helps manage Gradle installations. This step grants execute permission to the gradlew file which allows this build process to execute Gradle commands, needed for the next steps.
Set up JDK – This sets up the JDK as the Java envrionment for the build process. Make sure this matches the Java version you have chosen to use for this tutorial.
Build with Gradle – This executes the Gradle build process which will compile our Java code and package it into a JAR file which will then be used by the last job to push to the Container Registry.
The final workflow file should look like this:
name: Trigger auto deployment
# When this action will be executed
on:
# Automatically trigger it when detected changes in repo
push:
branches:
[ master ]
paths:
– ‘**’
– ‘.github/workflows/AutoDeployTrigger-aec369b2-f21b-47f6-8915-0d087617a092.yml’
# Allow manual trigger
workflow_dispatch:
jobs:
build-and-deploy:
runs-on: ubuntu-latest
permissions:
id-token: write #This is required for requesting the OIDC JWT Token
contents: read #Required when GH token is used to authenticate with private repo
steps:
– name: Checkout to the branch
uses: actions/checkout@v2
– name: Grant execute permission for gradlew
run: chmod +x gradlew
– name: Set up JDK 21
uses: actions/setup-java@v2
with:
java-version: ’21’
distribution: ‘adopt’
– name: Build with Gradle
run: ./gradlew build
– name: Azure Login
uses: azure/login@v1
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
– name: Build and push container image to registry
uses: azure/container-apps-deploy-action@v2
with:
appSourcePath: ${{ github.workspace }}
_dockerfilePathKey_: _dockerfilePath_
registryUrl: fdcontainers.azurecr.io
registryUsername: ${{ secrets.REGISTRY_USERNAME }}
registryPassword: ${{ secrets.REGISTRY_PASSWORD }}
containerAppName: epp-api
resourceGroup: registrar
imageToBuild: registrarcontainers.azurecr.io/fdspring:${{ github.sha }}
_buildArgumentsKey_: |
_buildArgumentsValues_
Conclusion
That is it! You have successfully built a robust EPP API using Kotlin and Spring Boot and now containerised it with Docker and deployed it to Azure Container Apps. This journey took us from understanding the intricacies of EPP and domain registration, through implementing core EPP operations, to creating a user-friendly RESTful API. We then containerised our application, ensuring consistency across different environments. Finally, we leveraged Azure’s powerful cloud service services – Azure Container Registry for storing our Docker image, and Azure Container Apps for deploying and running our application in a scalable, managed environment. The result is a fully functional, cloud-hosted API that can handle domain checks, registrations and other EPP operations. This accomplishment not only showcases the technical implementation but also opens up possibilities for creating sophisticated domain management tools and services, such as by starting a public registrar or managing a domain portfolio internally.
I hope this blog was useful, and I am happy to answer any questions in the replies. Well done on bringing this complex system to life!
Microsoft Tech Community – Latest Blogs –Read More
Remove deleted files.
Hi,
How do you remove files/dokuments from the list “Latest”, that no longer exist at my onedrive or my computer??
Thank you.
Hi,How do you remove files/dokuments from the list “Latest”, that no longer exist at my onedrive or my computer??Thank you. Read More
Teams Mobile – “Custom Notifications” NOT WORKING
When selecting “Notifications > Notify me for > Customized”, I am just being sent to the Android app notifications for this app, which does not have anything to do with custom notifications, only Permissions, where all the necessary allowances are given.
It has been like this for months…
This used to work on my old S21 ..
TLDR ; If I select customized > I am being sent to Android app notification permissions?!
Selecting this sends me to Android app notifications permissions, not custom notifications.The Android app notifications permissions where you cannot select what you are notified about.
Samsung Galaxy S24U, Mobile app is up to date.
When selecting “Notifications > Notify me for > Customized”, I am just being sent to the Android app notifications for this app, which does not have anything to do with custom notifications, only Permissions, where all the necessary allowances are given.It has been like this for months…This used to work on my old S21 .. TLDR ; If I select customized > I am being sent to Android app notification permissions?! Selecting this sends me to Android app notifications permissions, not custom notifications.The Android app notifications permissions where you cannot select what you are notified about. Samsung Galaxy S24U, Mobile app is up to date. Read More